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 ;
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 ;
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
{
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 ;
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 ; }
}
2010-12-03 00:08:58 +00:00
/// <summary>
/// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
/// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
/// </summary>
public bool HasGroupChangedDueToDelink { get ; private set ; }
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 ;
}
2008-11-01 21:50:07 +00:00
/// <value>
/// Is this scene object acting as an attachment?
///
/// We return false if the group has already been deleted.
2009-10-01 00:38:36 +00:00
///
2008-11-01 21:50:07 +00:00
/// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
/// presume either all or no parts in a linkset can be part of an attachment (in which
/// case the value would get proprogated down into all the descendent parts).
/// </value>
public bool IsAttachment
{
get
{
if ( ! IsDeleted )
return m_rootPart . IsAttachment ;
return false ;
}
}
2008-08-18 00:39:10 +00:00
2010-09-17 00:30:46 +00:00
public float scriptScore ;
2008-05-16 01:22:11 +00:00
2008-09-06 07:52:41 +00:00
private Vector3 lastPhysGroupPos ;
private Quaternion lastPhysGroupRot ;
2007-11-03 19:33:00 +00:00
2010-09-17 00:30:46 +00:00
private bool m_isBackedUp ;
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
{
2008-10-18 05:51:36 +00:00
get {
if ( RootPart = = null )
2010-09-17 00:30:46 +00:00
return String . Empty ;
2008-10-18 05:51:36 +00:00
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
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-11-05 00:08:10 +00:00
protected Quaternion m_rotation = Quaternion . Identity ;
public virtual Quaternion Rotation
{
get { return m_rotation ; }
set { m_rotation = value ; }
}
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
{
Vector3 minScale = new Vector3 ( Constants . RegionSize , Constants . RegionSize , Constants . RegionSize ) ;
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
}
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>
/// 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.
/// <returns></returns>
public bool IsAttachmentCheckFull ( )
2009-09-25 20:06:04 +00:00
{
return ( IsAttachment | | ( m_rootPart . Shape . PCode = = 9 & & m_rootPart . Shape . State ! = 0 ) ) ;
}
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
{
2011-04-14 16:33:55 +00:00
if ( ( Scene . TestBorderCross ( val - Vector3 . UnitX , Cardinals . E ) | | Scene . TestBorderCross ( val + Vector3 . UnitX , Cardinals . W )
| | Scene . TestBorderCross ( val - Vector3 . UnitY , Cardinals . N ) | | Scene . TestBorderCross ( val + Vector3 . UnitY , Cardinals . S ) )
& & ! IsAttachmentCheckFull ( ) & & ( ! Scene . LoadingPrims ) )
{
m_scene . CrossPrimGroupIntoNewRegion ( val , this , true ) ;
}
2007-08-24 12:34:00 +00:00
}
2010-08-25 23:08:53 +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
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
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
}
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
2007-09-13 05:25:26 +00:00
protected virtual bool InSceneBackup
{
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
private bool m_passCollision ;
public bool PassCollision
{
get { return m_passCollision ; }
set
{
m_passCollision = value ;
HasGroupChanged = true ;
}
}
2007-09-13 05:25:26 +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
2009-09-16 22:06:08 +00:00
if ( m_rootPart . PhysActor ! = null )
2008-01-29 15:10:18 +00:00
{
m_rootPart . PhysActor . 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 ] ;
2008-02-23 11:42:55 +00:00
if ( child . PhysActor ! = null )
child . PhysActor . 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 ; }
}
2007-08-20 16:07:37 +00:00
// The UUID for the Region this Object is in.
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
2007-08-13 13:36:42 +00:00
# endregion
2011-06-10 19:40:14 +00:00
// ~SceneObjectGroup()
// {
// m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId);
// }
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>
2008-11-07 19:49:22 +00:00
public SceneObjectGroup ( SceneObjectPart part )
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>
2008-11-07 21:07:14 +00:00
public SceneObjectGroup ( UUID ownerID , Vector3 pos , Quaternion rot , PrimitiveBaseShape shape )
2009-09-16 22:06:08 +00:00
{
SetRootPart ( new SceneObjectPart ( ownerID , shape , pos , rot , Vector3 . Zero ) ) ;
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
}
}
2009-08-15 16:36:45 +00:00
public void SetFromItemID ( UUID AssetId )
2008-04-27 14:37:51 +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 ] . FromItemID = AssetId ;
2008-04-27 14:37:51 +00:00
}
2009-08-15 16:36:45 +00:00
public UUID GetFromItemID ( )
2008-04-27 14:37:51 +00:00
{
2009-09-16 22:06:08 +00:00
return m_rootPart . FromItemID ;
2008-04-27 14:37:51 +00:00
}
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
{
if ( InSceneBackup )
{
2008-07-25 17:48:58 +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
2008-10-18 05:51:36 +00:00
if ( ! m_isBackedUp )
m_scene . EventManager . OnBackup + = ProcessBackup ;
2009-01-29 18:39:33 +00:00
2008-10-18 05:51:36 +00:00
m_isBackedUp = 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 ] ;
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
2009-09-30 16:00:09 +00:00
ApplyPhysics ( m_scene . m_physicalPrim ) ;
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 ;
minX = 256f ;
minY = 256f ;
2010-06-01 01:04:49 +00:00
minZ = 8192f ;
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
}
2008-04-26 17:36:30 +00:00
public byte GetAttachmentPoint ( )
{
2009-09-16 22:06:08 +00:00
return m_rootPart . Shape . State ;
2008-04-26 17:36:30 +00:00
}
2008-04-24 11:32:41 +00:00
2008-04-29 13:12:36 +00:00
public void ClearPartAttachmentData ( )
{
2008-10-03 21:44:33 +00:00
SetAttachmentPoint ( ( Byte ) 0 ) ;
2008-04-29 13:12:36 +00:00
}
2008-04-24 11:32:41 +00:00
public void DetachToGround ( )
{
2008-07-26 21:22:15 +00:00
ScenePresence avatar = m_scene . GetScenePresence ( m_rootPart . AttachedAvatar ) ;
2008-11-14 15:30:15 +00:00
if ( avatar = = null )
return ;
avatar . RemoveAttachment ( this ) ;
2008-09-06 07:52:41 +00:00
Vector3 detachedpos = new Vector3 ( 127f , 127f , 127f ) ;
2008-10-04 01:09:22 +00:00
if ( avatar = = null )
return ;
detachedpos = avatar . AbsolutePosition ;
2010-06-09 19:51:24 +00:00
RootPart . FromItemID = UUID . Zero ;
2008-10-04 01:09:22 +00:00
2008-04-24 11:32:41 +00:00
AbsolutePosition = detachedpos ;
2008-09-06 07:52:41 +00:00
m_rootPart . AttachedAvatar = UUID . Zero ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . AttachedAvatar = UUID . Zero ;
2009-07-02 16:02:18 +00:00
2008-04-24 11:32:41 +00:00
m_rootPart . SetParentLocalId ( 0 ) ;
2008-10-03 21:44:33 +00:00
SetAttachmentPoint ( ( byte ) 0 ) ;
2008-12-22 09:29:59 +00:00
m_rootPart . ApplyPhysics ( m_rootPart . GetEffectiveObjectFlags ( ) , m_rootPart . VolumeDetectActive , m_scene . m_physicalPrim ) ;
2008-06-27 16:36:19 +00:00
HasGroupChanged = true ;
2008-10-18 05:51:36 +00:00
RootPart . Rezzed = DateTime . Now ;
2008-11-10 16:11:22 +00:00
RootPart . RemFlag ( PrimFlags . TemporaryOnRez ) ;
2008-04-26 17:36:30 +00:00
AttachToBackup ( ) ;
2008-10-04 01:09:22 +00:00
m_scene . EventManager . TriggerParcelPrimCountTainted ( ) ;
2008-04-24 11:32:41 +00:00
m_rootPart . ScheduleFullUpdate ( ) ;
2008-04-28 01:48:21 +00:00
m_rootPart . ClearUndoState ( ) ;
2008-04-24 11:32:41 +00:00
}
2008-08-18 00:39:10 +00:00
2008-04-27 20:10:28 +00:00
public void DetachToInventoryPrep ( )
{
2008-07-26 21:22:15 +00:00
ScenePresence avatar = m_scene . GetScenePresence ( m_rootPart . AttachedAvatar ) ;
2008-09-06 07:52:41 +00:00
//Vector3 detachedpos = new Vector3(127f, 127f, 127f);
2008-04-27 20:10:28 +00:00
if ( avatar ! = null )
{
//detachedpos = avatar.AbsolutePosition;
avatar . RemoveAttachment ( this ) ;
}
2008-05-16 01:22:11 +00:00
2008-09-06 07:52:41 +00:00
m_rootPart . AttachedAvatar = UUID . Zero ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . AttachedAvatar = UUID . Zero ;
2009-07-02 16:02:18 +00:00
2008-04-27 20:10:28 +00:00
m_rootPart . SetParentLocalId ( 0 ) ;
//m_rootPart.SetAttachmentPoint((byte)0);
2008-07-26 21:22:15 +00:00
m_rootPart . IsAttachment = false ;
AbsolutePosition = m_rootPart . AttachedPos ;
2008-04-30 16:52:12 +00:00
//m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
2008-04-27 20:10:28 +00:00
//AttachToBackup();
//m_rootPart.ScheduleFullUpdate();
}
2009-08-14 08:16:41 +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
2008-04-21 14:11:36 +00:00
public override void UpdateMovement ( )
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . UpdateMovement ( ) ;
2008-04-21 14:11:36 +00:00
}
2007-08-13 18:25:12 +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
}
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// Added as a way for the storage provider to reset the scene,
2008-04-21 14:11:36 +00:00
/// most likely a better way to do this sort of thing but for now...
/// </summary>
/// <param name="scene"></param>
public void SetScene ( Scene scene )
{
m_scene = scene ;
2007-08-03 14:47:38 +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 ) ;
if ( part . LinkNum = = 2 & & RootPart ! = null )
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-04-28 01:48:21 +00:00
// helper provided for parts.
public int GetSceneMaxUndo ( )
{
if ( m_scene ! = null )
return m_scene . MaxUndoCount ;
return 5 ;
}
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 ( )
{
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localId ) ;
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>
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.
///
/// <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 ] ;
2010-09-15 20:41:42 +00:00
Scene . ForEachScenePresence ( delegate ( ScenePresence avatar )
2007-11-03 19:33:00 +00:00
{
2010-09-15 20:41:42 +00:00
if ( avatar . ParentID = = LocalId )
avatar . StandUp ( ) ;
2008-04-21 14:11:36 +00:00
2010-09-15 20:41:42 +00:00
if ( ! silent )
{
part . UpdateFlag = 0 ;
if ( part = = m_rootPart )
avatar . ControllingClient . SendKillObject ( m_regionHandle , part . LocalId ) ;
}
} ) ;
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
{
2008-05-25 20:50:45 +00:00
if ( scriptScore + count > = float . MaxValue - count )
scriptScore = 0 ;
scriptScore + = ( float ) count ;
2009-02-20 17:18:07 +00:00
SceneGraph d = m_scene . SceneGraph ;
2008-04-21 14:11:36 +00:00
d . 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>
/// <param name="m_physicalPrim"></param>
2008-04-21 14:11:36 +00:00
public void ApplyPhysics ( bool m_physicalPrim )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
// Apply physics to the root prim
m_rootPart . ApplyPhysics ( m_rootPart . GetEffectiveObjectFlags ( ) , m_rootPart . VolumeDetectActive , m_physicalPrim ) ;
// 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 )
part . ApplyPhysics ( m_rootPart . GetEffectiveObjectFlags ( ) , part . VolumeDetectActive , m_physicalPrim ) ;
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
{
2008-11-16 00:47:21 +00:00
if ( ! m_isBackedUp )
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 ) ;
m_scene . AddReturn ( 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 ;
2010-12-03 00:08:58 +00:00
HasGroupChangedDueToDelink = 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
2008-11-07 05:48:44 +00:00
public void SendFullUpdateToClient ( IClientAPI remoteClient )
2008-04-21 14:11:36 +00:00
{
2010-03-03 23:29:09 +00:00
RootPart . SendFullUpdate (
remoteClient , m_scene . Permissions . GenerateClientFlags ( remoteClient . AgentId , RootPart . UUID ) ) ;
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 )
part . SendFullUpdate ( remoteClient , m_scene . Permissions . GenerateClientFlags ( remoteClient . AgentId , part . UUID ) ) ;
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
{
2009-02-03 17:50:25 +00:00
SceneObjectGroup dupe = ( SceneObjectGroup ) MemberwiseClone ( ) ;
2008-10-20 22:14:24 +00:00
dupe . m_isBackedUp = false ;
2010-09-17 00:57:00 +00:00
dupe . m_parts = new MapAndArray < OpenMetaverse . UUID , SceneObjectPart > ( ) ;
2009-09-01 00:07:33 +00:00
// Warning, The following code related to previousAttachmentStatus is needed so that clones of
// attachments do not bordercross while they're being duplicated. This is hacktastic!
// Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
// unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
// (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
// then restore it's attachment state
// This is only necessary when userExposed is false!
bool previousAttachmentStatus = dupe . RootPart . IsAttachment ;
if ( ! userExposed )
dupe . RootPart . IsAttachment = true ;
2008-09-06 07:52:41 +00:00
dupe . AbsolutePosition = new Vector3 ( AbsolutePosition . X , AbsolutePosition . Y , AbsolutePosition . Z ) ;
2007-12-04 16:41:20 +00:00
2009-09-01 00:07:33 +00:00
if ( ! userExposed )
2010-06-27 23:29:30 +00:00
{
2009-09-01 00:07:33 +00:00
dupe . RootPart . IsAttachment = previousAttachmentStatus ;
2010-06-27 23:29:30 +00:00
}
2009-09-01 00:07:33 +00:00
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
2010-08-10 19:15:44 +00:00
if ( part . PhysActor ! = null & & userExposed )
{
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 ,
2011-07-15 19:07:59 +00:00
part . PhysActor . IsPhysical ,
newPart . LocalId ) ;
2010-08-10 19:15:44 +00:00
2011-06-15 18:26:45 +00:00
newPart . DoPhysicsPropertyUpdate ( part . PhysActor . IsPhysical , true ) ;
2010-09-12 17:43:49 +00:00
}
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
2008-04-21 14:11:36 +00:00
public void ScriptSetPhysicsStatus ( bool UsePhysics )
{
2008-11-07 22:57:32 +00:00
bool IsTemporary = ( ( RootPart . Flags & PrimFlags . TemporaryOnRez ) ! = 0 ) ;
bool IsPhantom = ( ( RootPart . Flags & PrimFlags . Phantom ) ! = 0 ) ;
2008-12-20 21:36:42 +00:00
bool IsVolumeDetect = RootPart . VolumeDetectActive ;
UpdatePrimFlags ( RootPart . LocalId , UsePhysics , IsTemporary , IsPhantom , IsVolumeDetect ) ;
2008-11-07 22:57:32 +00:00
}
2007-08-21 16:25:57 +00:00
2008-11-07 22:57:32 +00:00
public void ScriptSetTemporaryStatus ( bool TemporaryStatus )
{
bool UsePhysics = ( ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ) ;
bool IsPhantom = ( ( RootPart . Flags & PrimFlags . Phantom ) ! = 0 ) ;
2008-12-20 21:36:42 +00:00
bool IsVolumeDetect = RootPart . VolumeDetectActive ;
UpdatePrimFlags ( RootPart . LocalId , UsePhysics , TemporaryStatus , IsPhantom , IsVolumeDetect ) ;
2007-08-20 15:49:06 +00:00
}
2008-04-21 14:11:36 +00:00
public void ScriptSetPhantomStatus ( bool PhantomStatus )
2007-07-30 20:11:40 +00:00
{
2008-11-07 22:57:32 +00:00
bool UsePhysics = ( ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ) ;
bool IsTemporary = ( ( RootPart . Flags & PrimFlags . TemporaryOnRez ) ! = 0 ) ;
2008-12-20 21:36:42 +00:00
bool IsVolumeDetect = RootPart . VolumeDetectActive ;
UpdatePrimFlags ( RootPart . LocalId , UsePhysics , IsTemporary , PhantomStatus , IsVolumeDetect ) ;
}
public void ScriptSetVolumeDetect ( bool VDStatus )
{
bool UsePhysics = ( ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ) ;
bool IsTemporary = ( ( RootPart . Flags & PrimFlags . TemporaryOnRez ) ! = 0 ) ;
bool IsPhantom = ( ( RootPart . Flags & PrimFlags . Phantom ) ! = 0 ) ;
UpdatePrimFlags ( RootPart . LocalId , UsePhysics , IsTemporary , IsPhantom , VDStatus ) ;
/ *
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
{
2008-04-21 14:11:36 +00:00
// We check if rootpart is null here because scripts don't delete if you delete the host.
// This means that unfortunately, we can pass a null physics actor to Simulate!
// Make sure we don't do that!
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
2009-03-21 11:42:31 +00:00
if ( IsAttachment )
2008-04-21 14:11:36 +00:00
{
2009-03-21 11:42:31 +00:00
ScenePresence avatar = m_scene . GetScenePresence ( rootpart . AttachedAvatar ) ;
if ( avatar ! = null )
2008-05-06 00:23:19 +00:00
{
2009-03-21 11:42:31 +00:00
avatar . PushForce ( impulse ) ;
2008-05-06 00:23:19 +00:00
}
2009-03-21 11:42:31 +00:00
}
else
{
if ( rootpart . PhysActor ! = null )
2008-05-06 00:23:19 +00:00
{
2009-03-21 11:42:31 +00:00
rootpart . PhysActor . AddForce ( impulse , true ) ;
2008-05-06 00:23:19 +00:00
m_scene . PhysicsScene . AddPhysicsActorTaint ( rootpart . PhysActor ) ;
}
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
{
// We check if rootpart is null here because scripts don't delete if you delete the host.
// This means that unfortunately, we can pass a null physics actor to Simulate!
// Make sure we don't do that!
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
if ( rootpart . PhysActor ! = null )
{
if ( ! IsAttachment )
{
rootpart . PhysActor . AddAngularForce ( impulse , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( rootpart . PhysActor ) ;
}
}
}
}
2009-10-26 06:16:12 +00:00
public void setAngularImpulse ( Vector3 impulse )
2008-12-14 14:30:28 +00:00
{
// We check if rootpart is null here because scripts don't delete if you delete the host.
// This means that unfortunately, we can pass a null physics actor to Simulate!
// Make sure we don't do that!
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
if ( rootpart . PhysActor ! = null )
{
if ( ! IsAttachment )
{
rootpart . PhysActor . Torque = impulse ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( rootpart . PhysActor ) ;
}
}
}
}
public Vector3 GetTorque ( )
{
// We check if rootpart is null here because scripts don't delete if you delete the host.
// This means that unfortunately, we can pass a null physics actor to Simulate!
// Make sure we don't do that!
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
if ( rootpart . PhysActor ! = null )
{
if ( ! IsAttachment )
{
2009-10-26 06:16:12 +00:00
Vector3 torque = rootpart . PhysActor . Torque ;
return torque ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
2007-08-13 14:39:12 +00:00
{
2009-04-22 14:44:19 +00:00
if ( IsAttachment )
{
ScenePresence avatar = m_scene . GetScenePresence ( rootpart . AttachedAvatar ) ;
if ( avatar ! = null )
{
List < string > coords = new List < string > ( ) ;
uint regionX = 0 ;
uint regionY = 0 ;
Utils . LongToUInts ( Scene . RegionInfo . RegionHandle , out regionX , out regionY ) ;
target . X + = regionX ;
target . Y + = regionY ;
coords . Add ( target . X . ToString ( ) ) ;
coords . Add ( target . Y . ToString ( ) ) ;
coords . Add ( target . Z . ToString ( ) ) ;
avatar . DoMoveToPosition ( avatar , "" , coords ) ;
}
}
else
2008-04-23 15:32:19 +00:00
{
2009-04-22 14:44:19 +00:00
if ( rootpart . PhysActor ! = null )
{
2009-10-26 06:16:12 +00:00
rootpart . PhysActor . PIDTarget = target ;
2009-04-22 14:44:19 +00:00
rootpart . PhysActor . PIDTau = tau ;
rootpart . PhysActor . 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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
2007-08-09 17:54:22 +00:00
{
2008-10-22 14:06:07 +00:00
if ( rootpart . PhysActor ! = null )
{
rootpart . PhysActor . PIDActive = false ;
}
2007-08-09 17:54:22 +00:00
}
}
2009-12-22 00:26:12 +00:00
public void stopLookAt ( )
{
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
if ( rootpart . PhysActor ! = null )
{
rootpart . PhysActor . APIDActive = false ;
}
}
}
2007-08-09 17:54:22 +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 )
{
SceneObjectPart rootpart = m_rootPart ;
if ( rootpart ! = null )
{
if ( rootpart . PhysActor ! = null )
{
if ( height ! = 0f )
{
rootpart . PhysActor . PIDHoverHeight = height ;
rootpart . PhysActor . PIDHoverType = hoverType ;
rootpart . PhysActor . PIDTau = tau ;
rootpart . PhysActor . PIDHoverActive = true ;
}
else
{
rootpart . PhysActor . PIDHoverActive = false ;
}
}
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.
2008-05-16 01:22:11 +00:00
///
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.
2007-08-03 11:44:30 +00:00
/// </summary>
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
#region Scheduling
2007-09-19 00:30:55 +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.
if ( m_isDeleted )
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
2010-08-27 23:40:33 +00:00
bool UsePhysics = ( ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ) ;
2008-11-10 05:21:51 +00:00
2010-08-27 23:40:33 +00:00
if ( UsePhysics & & ! AbsolutePosition . ApproxEquals ( lastPhysGroupPos , 0.02f ) )
{
m_rootPart . UpdateFlag = 1 ;
lastPhysGroupPos = AbsolutePosition ;
}
2007-09-19 00:30:55 +00:00
2010-08-27 23:40:33 +00:00
if ( UsePhysics & & ! GroupRotation . ApproxEquals ( lastPhysGroupRot , 0.1f ) )
{
m_rootPart . UpdateFlag = 1 ;
lastPhysGroupRot = GroupRotation ;
}
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
public void ScheduleFullUpdateToAvatar ( ScenePresence presence )
2008-04-19 21:01:26 +00:00
{
2010-03-03 22:14:06 +00:00
// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1} just to avatar {2}", Name, UUID, presence.Name);
2008-11-07 05:48:44 +00:00
RootPart . AddFullUpdateToAvatar ( presence ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-04-19 21:01:26 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part ! = RootPart )
part . AddFullUpdateToAvatar ( presence ) ;
2008-04-19 21:01:26 +00:00
}
}
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
public void ScheduleTerseUpdateToAvatar ( ScenePresence presence )
2007-07-30 20:11:40 +00:00
{
2010-03-03 22:14:06 +00:00
// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name);
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . AddTerseUpdateToAvatar ( presence ) ;
2007-07-30 20:11:40 +00:00
}
2007-08-03 11:44:30 +00:00
/// <summary>
2008-06-27 14:15:14 +00:00
/// Schedule a full update for this scene object
2007-08-03 11:44:30 +00:00
/// </summary>
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>
2008-06-27 14:15:14 +00:00
/// Schedule a terse update for this scene object
2007-08-03 11:44:30 +00:00
/// </summary>
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
}
2007-07-30 20:11:40 +00:00
# endregion
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>
/// <returns>null if a child part with the primID was not found</returns>
2008-09-06 07:52:41 +00:00
public SceneObjectPart GetChildPart ( 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>
2008-04-21 14:11:36 +00:00
/// <returns>null if a child part with the local ID was not found</returns>
public SceneObjectPart GetChildPart ( 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
/// <summary>
2008-04-21 14:11:36 +00:00
/// Does this group contain the child prim
/// should be able to remove these methods once we have a entity index in scene
2007-08-03 11:44:30 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="primID"></param>
/// <returns></returns>
2008-09-06 07:52:41 +00:00
public bool HasChildPrim ( UUID primID )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
return m_parts . ContainsKey ( primID ) ;
2008-04-21 14:11:36 +00:00
}
2007-07-30 20:11:40 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
/// Does this group contain the child prim
/// should be able to remove these methods once we have a entity index in scene
/// </summary>
/// <param name="localID"></param>
/// <returns></returns>
public bool HasChildPrim ( uint localID )
{
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 true ;
2007-07-30 20:11:40 +00:00
}
2008-08-18 00:39:10 +00:00
2008-04-21 14:11:36 +00:00
return false ;
2007-07-30 20:11:40 +00:00
}
2007-09-19 00:30:55 +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>
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
{
2009-02-25 12:26:00 +00:00
// Make sure we have sent any pending unlinks or stuff.
2009-12-06 00:50:28 +00:00
//if (objectGroup.RootPart.UpdateFlag > 0)
//{
// m_log.WarnFormat(
// "[SCENE OBJECT GROUP]: Forcing send of linkset {0}, {1} to {2}, {3} as its still waiting.",
// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
// objectGroup.RootPart.SendScheduledUpdates();
//}
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);
SceneObjectPart linkPart = objectGroup . m_rootPart ;
2008-09-06 07:52:41 +00:00
Vector3 oldGroupPosition = linkPart . GroupPosition ;
Quaternion oldRootRotation = linkPart . RotationOffset ;
2008-04-21 14:11:36 +00:00
linkPart . OffsetPosition = linkPart . GroupPosition - AbsolutePosition ;
linkPart . GroupPosition = AbsolutePosition ;
2008-09-06 07:52:41 +00:00
Vector3 axPos = linkPart . OffsetPosition ;
2008-04-21 14:11:36 +00:00
2008-09-06 07:52:41 +00:00
Quaternion parentRot = m_rootPart . RotationOffset ;
axPos * = Quaternion . Inverse ( parentRot ) ;
2008-04-21 14:11:36 +00:00
2008-09-06 07:52:41 +00:00
linkPart . OffsetPosition = axPos ;
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
linkPart . ParentID = m_rootPart . LocalId ;
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
{
m_parts . Add ( linkPart . UUID , linkPart ) ;
2008-10-29 03:22:54 +00:00
// Insert in terms of link numbers, the new links
// before the current ones (with the exception of
// the root prim. Shuffle the old ones up
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-10-29 03:22:54 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part . LinkNum ! = 1 )
2008-10-29 03:22:54 +00:00
{
// Don't update root prim link number
2010-09-17 00:30:46 +00:00
part . LinkNum + = objectGroup . PrimCount ;
2008-10-29 03:22:54 +00:00
}
}
linkPart . LinkNum = 2 ;
linkPart . SetParent ( this ) ;
2010-05-31 17:00:02 +00:00
linkPart . CreateSelected = true ;
2008-10-29 03:22:54 +00:00
//if (linkPart.PhysActor != null)
//{
// m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2010-09-17 00:30:46 +00:00
2008-10-29 03:22:54 +00:00
//linkPart.PhysActor = null;
//}
//TODO: rest of parts
int linkNum = 3 ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] ogParts = objectGroup . Parts ;
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 )
LinkNonRootPart ( part , oldGroupPosition , oldRootRotation , linkNum + + ) ;
part . ClearUndoState ( ) ;
}
}
2008-04-21 14:11:36 +00:00
2010-09-06 23:34:06 +00:00
m_scene . UnlinkSceneObject ( objectGroup , true ) ;
2009-02-03 19:36:57 +00:00
objectGroup . m_isDeleted = true ;
2010-09-17 00:30:46 +00:00
objectGroup . m_parts . Clear ( ) ;
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
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>
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>
/// <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
{
SceneObjectPart linkPart = GetChildPart ( 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>
/// <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
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 ( ) ;
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
2009-04-29 15:54:16 +00:00
if ( linkPart . PhysActor ! = null )
{
m_scene . PhysicsScene . RemovePrim ( linkPart . PhysActor ) ;
}
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
Quaternion parentRot = m_rootPart . RotationOffset ;
2008-09-06 07:52:41 +00:00
2009-04-29 15:54:16 +00:00
Vector3 axPos = linkPart . OffsetPosition ;
2008-09-06 07:52:41 +00:00
2009-04-29 15:54:16 +00:00
axPos * = parentRot ;
linkPart . OffsetPosition = new Vector3 ( axPos . X , axPos . Y , axPos . Z ) ;
linkPart . GroupPosition = AbsolutePosition + linkPart . OffsetPosition ;
linkPart . OffsetPosition = new Vector3 ( 0 , 0 , 0 ) ;
2008-04-21 14:11:36 +00:00
2009-04-29 15:54:16 +00:00
linkPart . RotationOffset = worldRot ;
2008-04-21 14:11:36 +00:00
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
2010-12-03 00:08:58 +00:00
// When we delete a group, we currently have to force persist to the database if the object id has changed
// (since delete works by deleting all rows which have a given object id)
objectGroup . HasGroupChangedDueToDelink = true ;
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
{
2008-10-18 05:51:36 +00:00
if ( m_isBackedUp )
m_scene . EventManager . OnBackup - = ProcessBackup ;
2008-11-07 21:07:14 +00:00
2008-10-18 05:51:36 +00:00
m_isBackedUp = false ;
2008-04-21 14:11:36 +00:00
}
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 ;
Quaternion worldRot = parentRot * oldRot ;
parentRot = oldGroupRotation ;
Vector3 axPos = part . OffsetPosition ;
axPos * = parentRot ;
part . OffsetPosition = axPos ;
part . GroupPosition = oldGroupPosition + part . OffsetPosition ;
part . OffsetPosition = Vector3 . Zero ;
part . RotationOffset = worldRot ;
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-04-21 14:11:36 +00:00
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
2008-12-21 14:50:58 +00:00
part . OffsetPosition = part . GroupPosition - AbsolutePosition ;
2008-04-21 14:11:36 +00:00
2008-09-06 07:52:41 +00:00
Quaternion rootRotation = m_rootPart . RotationOffset ;
2008-04-21 14:11:36 +00:00
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
2008-12-21 14:50:58 +00:00
parentRot = m_rootPart . RotationOffset ;
oldRot = part . RotationOffset ;
Quaternion newRot = Quaternion . Inverse ( parentRot ) * oldRot ;
part . RotationOffset = newRot ;
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>
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>
2008-09-06 07:52:41 +00:00
public void GrabMovement ( 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 ) )
{
if ( m_rootPart . PhysActor ! = null )
{
if ( m_rootPart . PhysActor . IsPhysical )
{
2010-02-14 21:41:57 +00:00
if ( ! m_rootPart . BlockGrab )
{
Vector3 llmoveforce = pos - AbsolutePosition ;
Vector3 grabforce = llmoveforce ;
grabforce = ( grabforce / 10 ) * m_rootPart . PhysActor . Mass ;
m_rootPart . PhysActor . AddForce ( grabforce , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( m_rootPart . PhysActor ) ;
}
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 ) )
{
if ( m_rootPart . PhysActor ! = null )
{
if ( m_rootPart . PhysActor . IsPhysical )
{
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 ) )
{
if ( m_rootPart . PhysActor ! = null )
{
if ( m_rootPart . PhysActor . IsPhysical )
{
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 ) ;
2009-04-10 06:39:52 +00:00
spinforce = ( spinforce / 8 ) * m_rootPart . PhysActor . Mass ; // 8 is an arbitrary torque scaling factor
m_rootPart . PhysActor . AddAngularForce ( spinforce , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( m_rootPart . PhysActor ) ;
}
}
else
{
//NonPhysicalSpinMovement(pos);
}
}
else
{
//NonPhysicalSpinMovement(pos);
}
}
}
2007-08-13 13:36:42 +00:00
/// <summary>
2008-04-26 20:31:01 +00:00
/// Return metadata about a prim (name, description, sale price, etc.)
2007-08-13 13:36:42 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="client"></param>
public void GetProperties ( IClientAPI client )
2007-08-13 13:36:42 +00:00
{
2008-05-17 00:06:35 +00:00
m_rootPart . GetProperties ( client ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( partID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2008-07-12 19:05:12 +00:00
SceneObjectPart selectionPart = GetChildPart ( localID ) ;
2008-08-18 00:39:10 +00:00
2011-07-11 01:18:19 +00:00
if ( SetTemporary )
2008-10-03 16:18:38 +00:00
{
2008-10-03 15:32:44 +00:00
DetachFromBackup ( ) ;
2008-10-03 16:18:38 +00:00
// Remove from database and parcel prim count
/ /
m_scene . DeleteFromStorage ( UUID ) ;
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 ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-08-13 13:36:42 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part . Scale . X > m_scene . RegionInfo . PhysPrimMax | |
part . Scale . Y > m_scene . RegionInfo . PhysPrimMax | |
part . Scale . Z > m_scene . RegionInfo . PhysPrimMax )
2008-07-10 03:13:29 +00:00
{
2010-09-17 00:30:46 +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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
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
{
2007-09-19 00:30:55 +00:00
SceneObjectPart part = GetChildPart ( 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
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
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . UpdatePermissions ( AgentID , field , localID , mask , addRemTF ) ;
2008-10-06 02:29:38 +00:00
2008-04-21 14:11:36 +00:00
HasGroupChanged = true ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( localID ) ;
if ( part ! = null )
{
part . UpdateShape ( shapeBlock ) ;
if ( part . PhysActor ! = null )
m_scene . PhysicsScene . AddPhysicsActorTaint ( part . PhysActor ) ;
}
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
2011-07-16 04:23:21 +00:00
scale . X = Math . Min ( scale . X , Scene . m_maxNonphys ) ;
scale . Y = Math . Min ( scale . Y , Scene . m_maxNonphys ) ;
scale . Z = Math . Min ( scale . Z , Scene . m_maxNonphys ) ;
2011-07-16 00:36:27 +00:00
2011-07-16 01:53:36 +00:00
if ( RootPart . PhysActor ! = null & & RootPart . PhysActor . IsPhysical )
{
2011-07-16 04:23:21 +00:00
scale . X = Math . Min ( scale . X , Scene . m_maxPhys ) ;
scale . Y = Math . Min ( scale . Y , Scene . m_maxPhys ) ;
scale . Z = Math . Min ( scale . Z , Scene . m_maxPhys ) ;
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 ) ;
SceneObjectPart [ ] parts ;
if ( x > 1.0f | | y > 1.0f | | z > 1.0f )
{
parts = m_parts . GetArray ( ) ;
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
2011-07-16 01:53:36 +00:00
if ( RootPart . PhysActor ! = null & & RootPart . PhysActor . IsPhysical )
{
if ( oldSize . X * x > m_scene . m_maxPhys )
{
f = m_scene . m_maxPhys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2011-07-16 01:53:36 +00:00
if ( oldSize . Y * y > m_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
}
2011-07-18 03:54:21 +00:00
2011-07-16 01:53:36 +00:00
if ( oldSize . Z * z > m_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
}
}
2011-07-16 01:53:36 +00:00
else
{
if ( oldSize . X * x > m_scene . m_maxNonphys )
{
f = m_scene . m_maxNonphys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2011-07-16 01:53:36 +00:00
if ( oldSize . Y * y > m_scene . m_maxNonphys )
{
f = m_scene . m_maxNonphys / oldSize . Y ;
a = f / y ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2011-07-16 01:53:36 +00:00
if ( oldSize . Z * z > m_scene . m_maxNonphys )
{
f = m_scene . m_maxNonphys / oldSize . Z ;
a = f / z ;
x * = a ;
y * = a ;
z * = a ;
}
}
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 ;
RootPart . Resize ( prevScale ) ;
2008-04-21 14:11:36 +00:00
2011-07-16 01:53:36 +00:00
parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
{
SceneObjectPart obPart = parts [ i ] ;
2011-07-18 03:54:21 +00:00
// obPart.IgnoreUndoUpdate = true;
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-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-16 03:49:21 +00:00
2011-07-16 01:53:36 +00:00
obPart . Resize ( newSize ) ;
2011-07-18 03:54:21 +00:00
obPart . IgnoreUndoUpdate = true ;
2011-07-16 01:53:36 +00:00
obPart . UpdateOffSet ( currentpos ) ;
2011-07-18 03:54:21 +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);
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 ( 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
}
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-04-21 14:11:36 +00:00
AbsolutePosition = pos ;
2008-08-18 00:39:10 +00:00
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)
ScheduleGroupForTerseUpdate ( ) ;
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( 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 )
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);
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 ;
2008-04-20 04:19:44 +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="pos"></param>
2008-09-06 07:52:41 +00:00
private void UpdateRootPosition ( 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 root position of {0} {1} to {2}", Name, LocalId, pos);
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-09-06 07:52:41 +00:00
Vector3 newPos = new Vector3 ( pos . X , pos . Y , pos . Z ) ;
Vector3 oldPos =
new Vector3 ( AbsolutePosition . X + m_rootPart . OffsetPosition . X ,
2008-04-21 14:11:36 +00:00
AbsolutePosition . Y + m_rootPart . OffsetPosition . Y ,
AbsolutePosition . Z + m_rootPart . OffsetPosition . Z ) ;
2008-09-06 07:52:41 +00:00
Vector3 diff = oldPos - newPos ;
2008-04-21 14:11:36 +00:00
Vector3 axDiff = new Vector3 ( diff . X , diff . Y , diff . Z ) ;
2008-09-06 07:52:41 +00:00
Quaternion partRotation = m_rootPart . RotationOffset ;
axDiff * = Quaternion . Inverse ( partRotation ) ;
diff = axDiff ;
2008-04-21 14:11:36 +00:00
2010-09-17 00:30:46 +00:00
parts = m_parts . GetArray ( ) ;
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 ;
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-09-06 07:52:41 +00:00
public void OffsetForNewRegion ( Vector3 offset )
2008-04-21 14:11:36 +00:00
{
m_rootPart . GroupPosition = offset ;
}
2008-04-20 04:19:44 +00:00
2008-04-21 14:11:36 +00:00
# endregion
#region Rotation
/// <summary>
2008-05-16 01:22:11 +00:00
///
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);
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
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>
2008-05-16 01:22:11 +00:00
///
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);
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
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
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 ( ) ;
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>
2008-05-16 01:22:11 +00:00
///
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
{
2008-04-21 14:11:36 +00:00
SceneObjectPart part = GetChildPart ( 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>
///
/// </summary>
/// <param name="rot"></param>
/// <param name="localID"></param>
public void UpdateSingleRotation ( Quaternion rot , Vector3 pos , uint localID )
{
SceneObjectPart part = GetChildPart ( localID ) ;
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);
2009-07-17 14:58:54 +00:00
if ( part . UUID = = m_rootPart . UUID )
{
UpdateRootRotation ( rot ) ;
AbsolutePosition = pos ;
}
else
{
2010-02-14 21:41:57 +00:00
part . IgnoreUndoUpdate = true ;
2009-07-17 14:58:54 +00:00
part . UpdateRotation ( rot ) ;
part . OffsetPosition = pos ;
2010-02-14 21:41:57 +00:00
part . IgnoreUndoUpdate = false ;
part . StoreUndoState ( ) ;
2009-07-17 14:58:54 +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="rot"></param>
2008-09-06 07:52:41 +00:00
private void UpdateRootRotation ( Quaternion rot )
2008-01-17 09:32:02 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
// Name, LocalId, rot);
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 ) ;
if ( m_rootPart . PhysActor ! = null )
{
2008-09-06 07:52:41 +00:00
m_rootPart . PhysActor . Orientation = m_rootPart . RotationOffset ;
2008-04-21 14:11:36 +00:00
m_scene . PhysicsScene . AddPhysicsActorTaint ( m_rootPart . PhysActor ) ;
}
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 ;
Quaternion newRot = primsRot * oldParentRot ;
newRot * = Quaternion . Inverse ( axRot ) ;
prim . RotationOffset = newRot ;
prim . ScheduleTerseUpdate ( ) ;
2008-01-21 15:06:49 +00:00
}
2008-01-17 09:32:02 +00:00
}
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2010-02-14 21:41:57 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart childpart = parts [ i ] ;
2010-02-14 21:41:57 +00:00
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 ( ) ;
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 ;
2009-09-30 16:51:02 +00:00
if ( m_rootPart ! = null )
{
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
2009-09-30 16:51:02 +00:00
float setval = ( rotate10 > 0 ) ? 1f : 0f ;
2008-05-01 18:04:42 +00:00
2009-09-30 16:51:02 +00:00
if ( setX )
m_rootPart . RotationAxis . X = setval ;
if ( setY )
m_rootPart . RotationAxis . Y = setval ;
if ( setZ )
m_rootPart . RotationAxis . Z = setval ;
if ( setX | | setY | | setZ )
{
m_rootPart . SetPhysicsAxisRotation ( ) ;
}
2008-05-01 18:04:42 +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 ] ;
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 ;
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>
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
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2011-07-11 02:35:29 +00:00
parts [ i ] . CheckSculptAndLoad ( ) ;
2008-05-09 07:50:00 +00:00
}
2008-08-18 00:39:10 +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
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
}
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
public void SetAttachmentPoint ( byte point )
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . SetAttachmentPoint ( point ) ;
2008-10-03 21:44:33 +00:00
}
2009-02-09 22:27:27 +00:00
#region ISceneObject
public virtual ISceneObject CloneForNewScene ( )
{
2010-06-27 23:48:24 +00:00
SceneObjectGroup sog = Copy ( false ) ;
2009-02-10 22:54:05 +00:00
sog . m_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 ( )
{
2009-08-15 16:36:45 +00:00
return "<ExtraFromItemID>" + GetFromItemID ( ) . 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 ) ;
2009-08-15 16:36:45 +00:00
SetFromItemID ( 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
}