From 385c1f51846197f03a535fe80c3fed131d03df5d Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Mon, 21 Apr 2008 14:11:36 +0000 Subject: * Added missing reference to OpenSim.Framework.Communications to RemoteAdminPlugin to fix a compile error introduced by the Radmin patch. --- .../Region/Environment/Scenes/SceneObjectGroup.cs | 2436 ++++++++++---------- 1 file changed, 1218 insertions(+), 1218 deletions(-) (limited to 'OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs') diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index ac35e46..6af7662 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -39,9 +39,8 @@ using OpenSim.Region.Physics.Manager; namespace OpenSim.Region.Environment.Scenes { - [Flags] - public enum scriptEvents : int + public enum scriptEvents { None = 0, attach = 1, @@ -77,16 +76,6 @@ namespace OpenSim.Region.Environment.Scenes public partial class SceneObjectGroup : EntityBase { - protected SceneObjectPart m_rootPart; - - /// - /// The constituent parts of this group - /// - protected Dictionary m_parts = new Dictionary(); - - protected ulong m_regionHandle; - - public event PrimCountTaintedDelegate OnPrimCountTainted; private PrimCountTaintedDelegate handlerPrimCountTainted = null; /// @@ -94,17 +83,34 @@ namespace OpenSim.Region.Environment.Scenes /// since the group's last persistent backup /// public bool HasGroupChanged = false; - + private LLVector3 lastPhysGroupPos; private LLQuaternion lastPhysGroupRot; - private Dictionary m_scriptEvents = new Dictionary(); private scriptEvents m_aggregateScriptEvents = scriptEvents.None; + /// + /// The constituent parts of this group + /// + protected Dictionary m_parts = new Dictionary(); + + protected ulong m_regionHandle; + protected SceneObjectPart m_rootPart; + private Dictionary m_scriptEvents = new Dictionary(); + #region Properties /// + /// 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 + /// saying what prim(s) that user has selected. + /// + protected bool m_isSelected = false; + + /// /// /// public int PrimCount @@ -116,11 +122,13 @@ namespace OpenSim.Region.Environment.Scenes { get { return m_rootPart.RotationOffset; } } + public LLUUID GroupID { get { return m_rootPart.GroupID; } set { m_rootPart.GroupID = value; } } + /// /// /// @@ -161,7 +169,7 @@ namespace OpenSim.Region.Environment.Scenes { get { - if( m_rootPart == null ) + if (m_rootPart == null) { throw new NullReferenceException( string.Format("[SCENE OBJECT GROUP]: Object {0} has no root part.", m_uuid)); @@ -176,7 +184,7 @@ namespace OpenSim.Region.Environment.Scenes { m_scene.CrossPrimGroupIntoNewRegion(val, this); } - + lock (m_parts) { @@ -187,24 +195,26 @@ namespace OpenSim.Region.Environment.Scenes } //if (m_rootPart.PhysActor != null) //{ - //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); + //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); //} } } public override uint LocalId { - get { + get + { if (m_rootPart == null) { m_log.Error("[SCENE OBJECT GROUP]: Unable to find the rootpart for a LocalId Request!"); return 0; } - - return m_rootPart.LocalId; } + + return m_rootPart.LocalId; + } set { m_rootPart.LocalId = value; } } @@ -216,11 +226,12 @@ namespace OpenSim.Region.Environment.Scenes public LLUUID OwnerID { - get { + get + { if (m_rootPart == null) return LLUUID.Zero; - return m_rootPart.OwnerID; + return m_rootPart.OwnerID; } set { m_rootPart.OwnerID = value; } } @@ -237,15 +248,6 @@ namespace OpenSim.Region.Environment.Scenes set { m_rootPart.Text = value; } } - /// - /// 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 - /// saying what prim(s) that user has selected. - /// - protected bool m_isSelected = false; - protected virtual bool InSceneBackup { get { return true; } @@ -254,7 +256,8 @@ namespace OpenSim.Region.Environment.Scenes public bool IsSelected { get { return m_isSelected; } - set { + set + { m_isSelected = value; // Tell physics engine that group is selected if (m_rootPart.PhysActor != null) @@ -304,11 +307,11 @@ namespace OpenSim.Region.Environment.Scenes public SceneObjectGroup(Scene scene, ulong regionHandle, SceneObjectPart part) { m_scene = scene; - + part.SetParent(this); part.ParentID = 0; part.LinkNum = 0; - + m_parts.Add(part.UUID, part); SetPartAsRoot(part); @@ -329,7 +332,7 @@ namespace OpenSim.Region.Environment.Scenes { m_scene = scene; m_regionHandle = regionHandle; - + StringReader sr = new StringReader(xmlData); XmlTextReader reader = new XmlTextReader(sr); try @@ -339,11 +342,11 @@ namespace OpenSim.Region.Environment.Scenes reader.ReadStartElement("RootPart"); m_rootPart = SceneObjectPart.FromXml(reader); AddPart(m_rootPart); - - m_log.DebugFormat("[SCENE OBJECT GROUP]: Current node {0}", reader.Name); - + + m_log.DebugFormat("[SCENE OBJECT GROUP]: Current node {0}", reader.Name); + reader.ReadEndElement(); - + while (reader.Read()) { switch (reader.NodeType) @@ -356,7 +359,7 @@ namespace OpenSim.Region.Environment.Scenes part.LocalId = m_scene.PrimIDAllocate(); AddPart(part); part.RegionHandle = m_regionHandle; - + part.TrimPermissions(); } break; @@ -368,10 +371,10 @@ namespace OpenSim.Region.Environment.Scenes catch (XmlException) { m_log.ErrorFormat("[SCENE OBJECT GROUP]: Deserialization of following xml failed, {0}", xmlData); - + // Let's see if carrying on does anything for us } - + reader.Close(); sr.Close(); @@ -436,6 +439,37 @@ namespace OpenSim.Region.Environment.Scenes } /// + /// + /// + public SceneObjectGroup(Scene scene, ulong regionHandle, LLUUID ownerID, uint localID, LLVector3 pos, + LLQuaternion rot, PrimitiveBaseShape shape) + { + m_regionHandle = regionHandle; + m_scene = scene; + + // this.Pos = pos; + LLVector3 rootOffset = new LLVector3(0, 0, 0); + SceneObjectPart newPart = + new SceneObjectPart(m_regionHandle, this, ownerID, localID, shape, pos, rot, rootOffset); + newPart.LinkNum = m_parts.Count; + m_parts.Add(newPart.UUID, newPart); + SetPartAsRoot(newPart); + + AttachToBackup(); + + //ApplyPhysics(scene.m_physicalPrim); + } + + /// + /// + /// + public SceneObjectGroup(Scene scene, ulong regionHandle, LLUUID ownerID, uint localID, LLVector3 pos, + PrimitiveBaseShape shape) + : this(scene, regionHandle, ownerID, localID, pos, LLQuaternion.Identity, shape) + { + } + + /// /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes. /// private void AttachToBackup() @@ -473,7 +507,7 @@ namespace OpenSim.Region.Environment.Scenes // 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 = (float)Constants.RegionSize; + float idist = Constants.RegionSize; if (inter.HitTF) @@ -481,7 +515,6 @@ namespace OpenSim.Region.Environment.Scenes // We need to find the closest prim to return to the testcaller along the ray if (inter.distance < idist) { - idist = inter.distance; returnresult.HitTF = true; returnresult.ipoint = inter.ipoint; returnresult.obj = part; @@ -494,39 +527,10 @@ namespace OpenSim.Region.Environment.Scenes return returnresult; } - /// - /// - /// - public SceneObjectGroup(Scene scene, ulong regionHandle, LLUUID ownerID, uint localID, LLVector3 pos, - LLQuaternion rot, PrimitiveBaseShape shape) - { - m_regionHandle = regionHandle; - m_scene = scene; - - // this.Pos = pos; - LLVector3 rootOffset = new LLVector3(0, 0, 0); - SceneObjectPart newPart = - new SceneObjectPart(m_regionHandle, this, ownerID, localID, shape, pos, rot, rootOffset); - newPart.LinkNum = m_parts.Count; - m_parts.Add(newPart.UUID, newPart); - SetPartAsRoot(newPart); - - AttachToBackup(); - - //ApplyPhysics(scene.m_physicalPrim); - } - - /// - /// - /// - public SceneObjectGroup(Scene scene, ulong regionHandle, LLUUID ownerID, uint localID, LLVector3 pos, - PrimitiveBaseShape shape) - : this(scene, regionHandle, ownerID, localID, pos, LLQuaternion.Identity, shape) - { - } - #endregion + public event PrimCountTaintedDelegate OnPrimCountTainted; + public string ToXmlString() { using (StringWriter sw = new StringWriter()) @@ -547,7 +551,7 @@ namespace OpenSim.Region.Environment.Scenes m_rootPart.ToXml(writer); writer.WriteEndElement(); writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); - + lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) @@ -560,7 +564,7 @@ namespace OpenSim.Region.Environment.Scenes } } } - + writer.WriteEndElement(); writer.WriteEndElement(); } @@ -583,7 +587,7 @@ namespace OpenSim.Region.Environment.Scenes writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); m_rootPart.ToXml(writer); writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); - + lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) @@ -594,1060 +598,771 @@ namespace OpenSim.Region.Environment.Scenes } } } - + writer.WriteEndElement(); writer.WriteEndElement(); } - #region Copying - /// - /// Duplicates this object, including operations such as physics set up and attaching to the backup event. + /// /// - /// - public SceneObjectGroup Copy(LLUUID cAgentID, LLUUID cGroupID) + /// + private void SetPartAsRoot(SceneObjectPart part) { - SceneObjectGroup dupe = (SceneObjectGroup) MemberwiseClone(); - dupe.m_parts = new Dictionary(); - dupe.m_parts.Clear(); - //dupe.OwnerID = AgentID; - //dupe.GroupID = GroupID; - dupe.AbsolutePosition = new LLVector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); - dupe.m_scene = m_scene; - dupe.m_regionHandle = m_regionHandle; - - dupe.CopyRootPart(m_rootPart, OwnerID, GroupID); - dupe.m_rootPart.TrimPermissions(); - - /// may need to create a new Physics actor. - if (dupe.RootPart.PhysActor != null) - { - PrimitiveBaseShape pbs = dupe.RootPart.Shape; - - dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape( - dupe.RootPart.Name, - pbs, - new PhysicsVector(dupe.RootPart.AbsolutePosition.X, dupe.RootPart.AbsolutePosition.Y, - dupe.RootPart.AbsolutePosition.Z), - new PhysicsVector(dupe.RootPart.Scale.X, dupe.RootPart.Scale.Y, dupe.RootPart.Scale.Z), - new Quaternion(dupe.RootPart.RotationOffset.W, dupe.RootPart.RotationOffset.X, - dupe.RootPart.RotationOffset.Y, dupe.RootPart.RotationOffset.Z), - dupe.RootPart.PhysActor.IsPhysical); - - dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId; - - dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true); - } - // Now we've made a copy that replaces this one, we need to - // switch the owner to the person who did the copying - // Second Life copies an object and duplicates the first one in it's place - // So, we have to make a copy of this one, set it in it's place then set the owner on this one - - SetRootPartOwner(m_rootPart, cAgentID, cGroupID); + m_rootPart = part; + } + /// + /// + /// + /// + private void SetPartAsNonRoot(SceneObjectPart part) + { + part.ParentID = m_rootPart.LocalId; + } - m_rootPart.ScheduleFullUpdate(); + /// + /// + /// + /// + public List GetScenePresences() + { + return m_scene.GetScenePresences(); + } - List partList = new List(m_parts.Values); - foreach (SceneObjectPart part in partList) + public override void UpdateMovement() + { + lock (m_parts) { - if (part.UUID != m_rootPart.UUID) + foreach (SceneObjectPart part in m_parts.Values) { - dupe.CopyPart(part, OwnerID, GroupID); - SetPartOwner(part, cAgentID, cGroupID); - part.ScheduleFullUpdate(); + part.UpdateMovement(); } } - dupe.UpdateParentIDs(); + } - dupe.AttachToBackup(); - ScheduleGroupForFullUpdate(); + public float GetTimeDilation() + { + return m_scene.TimeDilation; + } - return dupe; + /// + /// Added as a way for the storage provider to reset the scene, + /// most likely a better way to do this sort of thing but for now... + /// + /// + public void SetScene(Scene scene) + { + m_scene = scene; + AttachToBackup(); } /// /// /// /// - public void CopyRootPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) + public void AddPart(SceneObjectPart part) { - SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); - newPart.SetParent(this); - lock (m_parts) { - m_parts.Add(newPart.UUID, newPart); - } - - SetPartAsRoot(newPart); - } + part.SetParent(this); + part.LinkNum = m_parts.Count; - public void ScriptSetPhysicsStatus(bool UsePhysics) - { - if (m_scene.m_physicalPrim) - { - lock (m_parts) + try { - foreach (SceneObjectPart part in m_parts.Values) - { - if (UsePhysics) - part.AddFlag(LLObject.ObjectFlags.Physics); - else - part.RemFlag(LLObject.ObjectFlags.Physics); - - part.DoPhysicsPropertyUpdate(UsePhysics, false); - IsSelected = false; - } + m_parts.Add(part.UUID, part); + } + catch (Exception e) + { + m_log.Error("Failed to add scened object part", e); } } - } - public void ScriptSetPhantomStatus(bool PhantomStatus) + /// + /// + /// + public void UpdateParentIDs() { lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) { - if (PhantomStatus) + if (part.UUID != m_rootPart.UUID) { - part.AddFlag(LLObject.ObjectFlags.Phantom); - if (part.PhysActor != null) - { - m_scene.PhysicsScene.RemovePrim(part.PhysActor); - } - } - else - { - part.RemFlag(LLObject.ObjectFlags.Phantom); - if ((part.ObjectFlags & (int)LLObject.ObjectFlags.Physics) != 0) - { - part.DoPhysicsPropertyUpdate(true, false); - } + part.ParentID = m_rootPart.LocalId; } } } } - public void applyImpulse(PhysicsVector impulse) + public void RegenerateFullIDs() { - // 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) + lock (m_parts) { - if (rootpart.PhysActor != null) + foreach (SceneObjectPart part in m_parts.Values) { - rootpart.PhysActor.AddForce(impulse); - m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); + part.UUID = LLUUID.Random(); } } } - public void moveToTarget(LLVector3 target, float tau) - { - SceneObjectPart rootpart = m_rootPart; - if (rootpart != null) - { - rootpart.PhysActor.PIDTarget = new PhysicsVector(target.X, target.Y, target.Z); - rootpart.PhysActor.PIDTau = tau; - rootpart.PhysActor.PIDActive = true; - } - } - public void stopMoveToTarget() + public void ResetChildPrimPhysicsPositions() { - SceneObjectPart rootpart = m_rootPart; - if (rootpart != null) - { - rootpart.PhysActor.PIDActive = false; - } + AbsolutePosition = AbsolutePosition; + HasGroupChanged = false; } - public void SetRootPartOwner(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) + public LLUUID GetPartsFullID(uint localID) { - part.LastOwnerID = part.OwnerID; - part.OwnerID = cAgentID; - part.GroupID = cGroupID; - - - if (part.OwnerID != cAgentID) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - // Apply Next Owner Permissions if we're not bypassing permissions - if (!m_scene.PermissionsMngr.BypassPermissions) - m_rootPart.ApplyNextOwnerPermissions(); + return part.UUID; } - - part.ScheduleFullUpdate(); + return null; } - /// - /// - /// - /// - public void CopyPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) + public void ObjectGrabHandler(uint localId, LLVector3 offsetPos, IClientAPI remoteClient) { - SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); - newPart.SetParent(this); - - lock (m_parts) + if (m_rootPart.LocalId == localId) { - m_parts.Add(newPart.UUID, newPart); + OnGrabGroup(offsetPos, remoteClient); } - - SetPartAsNonRoot(newPart); - } - - /// - /// Reset the LLUUIDs for all the prims that make up this group. - /// - /// 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. - /// - public void ResetIDs() - { - // As this is only ever called for prims which are not currently part of the scene (and hence - // not accessible by clients), there should be no need to lock - List partsList = new List(m_parts.Values); - m_parts.Clear(); - foreach (SceneObjectPart part in partsList) + else { - part.ResetIDs(m_parts.Count); - m_parts.Add(part.UUID, part); + SceneObjectPart part = GetChildPart(localId); + OnGrabPart(part, offsetPos, remoteClient); } } - /// - /// - /// - /// - public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, LLUUID AgentID, uint RequestFlags) + public virtual void OnGrabPart(SceneObjectPart part, LLVector3 offsetPos, IClientAPI remoteClient) { - //RootPart.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags); - ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket) PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - objPropDB.RequestFlags = RequestFlags; - objPropDB.ObjectID = RootPart.UUID; - objPropDB.OwnerID = RootPart.ObjectOwner; - objPropDB.GroupID = RootPart.GroupID; - objPropDB.BaseMask = RootPart.BaseMask; - objPropDB.OwnerMask = RootPart.OwnerMask; - objPropDB.GroupMask = RootPart.GroupMask; - objPropDB.EveryoneMask = RootPart.EveryoneMask; - objPropDB.NextOwnerMask = RootPart.NextOwnerMask; - - // TODO: More properties are needed in SceneObjectPart! - objPropDB.OwnershipCost = RootPart.OwnershipCost; - objPropDB.SaleType = RootPart.ObjectSaleType; - objPropDB.SalePrice = RootPart.SalePrice; - objPropDB.Category = RootPart.Category; - objPropDB.LastOwnerID = RootPart.CreatorID; - objPropDB.Name = Helpers.StringToField(RootPart.Name); - objPropDB.Description = Helpers.StringToField(RootPart.Description); - objPropFamilyPack.ObjectData = objPropDB; - remoteClient.OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); + part.OnGrab(offsetPos, remoteClient); } - public void SetPartOwner(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) + public virtual void OnGrabGroup(LLVector3 offsetPos, IClientAPI remoteClient) { - part.OwnerID = cAgentID; - part.GroupID = cGroupID; + m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId); } - #endregion - - #region Scheduling - /// - /// Examine this object's parts to see if they've changed sufficiently to warrant an update + /// Completely delete this group and tell all the scene presences about that deletion. /// - public override void Update() + public void DeleteGroup() { + DetachFromBackup(this); + lock (m_parts) { - if (Util.GetDistanceTo(lastPhysGroupPos, AbsolutePosition) > 0.02) - { - foreach (SceneObjectPart part in m_parts.Values) - { - if (part.UpdateFlag == 0) part.UpdateFlag = 1; - } - - lastPhysGroupPos = AbsolutePosition; - } - - if ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) - || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) - || (Math.Abs(lastPhysGroupRot.Y - GroupRotation.Y) > 0.1) - || (Math.Abs(lastPhysGroupRot.Z - GroupRotation.Z) > 0.1)) + foreach (SceneObjectPart part in m_parts.Values) { - foreach (SceneObjectPart part in m_parts.Values) + List avatars = GetScenePresences(); + for (int i = 0; i < avatars.Count; i++) { - if (part.UpdateFlag == 0) part.UpdateFlag = 1; + if (avatars[i].ParentID == LocalId) + { + avatars[i].StandUp(); + } + + avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); } - - lastPhysGroupRot = GroupRotation; - } - - foreach (SceneObjectPart part in m_parts.Values) - { - part.SendScheduledUpdates(); } } } - public void ScheduleFullUpdateToAvatar(ScenePresence presence) + /// + /// Delete all the parts in this group. + /// + public void DeleteParts() { lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) { - part.AddFullUpdateToAvatar(presence); + part.StopScripts(); } + + m_rootPart = null; + m_parts.Clear(); } } - public void ScheduleTerseUpdateToAvatar(ScenePresence presence) + public void AddScriptLPS(int count) { - lock (m_parts) - { - foreach (SceneObjectPart part in m_parts.Values) - { - part.AddTerseUpdateToAvatar(presence); - } - } + InnerScene d = m_scene.m_innerScene; + d.AddToScriptLPS(count); } - /// - /// Schedule a full update for every part in this object - /// - public void ScheduleGroupForFullUpdate() + public void AddActiveScriptCount(int count) { - HasGroupChanged = true; - - lock (m_parts) - { - foreach (SceneObjectPart part in m_parts.Values) - { - part.ScheduleFullUpdate(); - } - } + InnerScene d = m_scene.m_innerScene; + d.AddActiveScripts(count); } - /// - /// - /// - public void ScheduleGroupForTerseUpdate() + public void RemoveScriptEvents(LLUUID scriptid) { - HasGroupChanged = true; - - lock (m_parts) + lock (m_scriptEvents) { - foreach (SceneObjectPart part in m_parts.Values) + if (m_scriptEvents.ContainsKey(scriptid)) { - part.ScheduleTerseUpdate(); + scriptEvents oldparts = scriptEvents.None; + oldparts = (scriptEvents) m_scriptEvents[scriptid]; + + // remove values from aggregated script events + m_aggregateScriptEvents &= ~oldparts; + m_scriptEvents.Remove(scriptid); } } + aggregateScriptEvents(); } - /// - /// - /// - public void SendGroupFullUpdate() + public void SetScriptEvents(LLUUID scriptid, int events) { - HasGroupChanged = true; - - lock (m_parts) + scriptEvents oldparts; + lock (m_scriptEvents) { - foreach (SceneObjectPart part in m_parts.Values) + if (m_scriptEvents.ContainsKey(scriptid)) { - part.SendFullUpdateToAllClients(); + oldparts = m_scriptEvents[scriptid]; + + // remove values from aggregated script events + m_aggregateScriptEvents &= ~oldparts; + m_scriptEvents[scriptid] = (scriptEvents) events; + } + else + { + m_scriptEvents.Add(scriptid, (scriptEvents) events); } } - } - public void QueueForUpdateCheck() - { - m_scene.m_innerScene.AddToUpdateList(this); + aggregateScriptEvents(); } - /// - /// - /// - public void SendGroupTerseUpdate() + public void aggregateScriptEvents() { - HasGroupChanged = true; - - lock (m_parts) + // Aggregate script events + lock (m_scriptEvents) { - foreach (SceneObjectPart part in m_parts.Values) + foreach (scriptEvents s in m_scriptEvents.Values) { - part.SendTerseUpdateToAllClients(); + m_aggregateScriptEvents |= s; } } - } + uint objectflagupdate = m_rootPart.ObjectFlags; - #endregion + if ( + ((m_aggregateScriptEvents & scriptEvents.touch) != 0) || + ((m_aggregateScriptEvents & scriptEvents.touch_end) != 0) || + ((m_aggregateScriptEvents & scriptEvents.touch_start) != 0) + ) + { + objectflagupdate |= (uint) LLObject.ObjectFlags.Touch; + } + else + { + objectflagupdate &= ~(uint) LLObject.ObjectFlags.Touch; + } - #region SceneGroupPart Methods + if ((m_aggregateScriptEvents & scriptEvents.money) != 0) + { + objectflagupdate |= (uint) LLObject.ObjectFlags.Money; + } + else + { + objectflagupdate &= ~(uint) LLObject.ObjectFlags.Money; + } - /// - /// Get the child part by LinkNum - /// - /// - /// null if no child part with that linknum or child part - public SceneObjectPart GetLinkNumPart(int linknum) - { + if ( + ((m_aggregateScriptEvents & scriptEvents.collision) != 0) || + ((m_aggregateScriptEvents & scriptEvents.collision_end) != 0) || + ((m_aggregateScriptEvents & scriptEvents.collision_start) != 0) + ) + { + // subscribe to physics updates. + } + else + { + // unsubscribe to physics updates. + } lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) { - if (part.LinkNum == linknum) - { - return part; - } + part.ObjectFlags = objectflagupdate; } } - - return null; + ScheduleGroupForFullUpdate(); } - /// - /// Get a child part with a given UUID - /// - /// - /// null if a child part with the primID was not found - public SceneObjectPart GetChildPart(LLUUID primID) + public override void SetText(string text, Vector3 color, double alpha) { - SceneObjectPart childPart = null; - if (m_parts.ContainsKey(primID)) - { - childPart = m_parts[primID]; - } - return childPart; + Color = Color.FromArgb(0xff - (int) (alpha * 0xff), + (int) (color.x * 0xff), + (int) (color.y * 0xff), + (int) (color.z * 0xff)); + Text = text; + + m_rootPart.ScheduleFullUpdate(); } - /// - /// Get a child part with a given local ID - /// - /// - /// null if a child part with the local ID was not found - public SceneObjectPart GetChildPart(uint localID) + public void ApplyPhysics(bool m_physicalPrim) { lock (m_parts) { - foreach (SceneObjectPart part in m_parts.Values) + if (m_parts.Count > 1) { - if (part.LocalId == localID) + m_rootPart.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); + foreach (SceneObjectPart part in m_parts.Values) { - return part; + if (part.LocalId != m_rootPart.LocalId) + { + part.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); + } + // Hack to get the physics scene geometries in the right spot + ResetChildPrimPhysicsPositions(); } } + else + { + m_rootPart.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); + } } - - return null; } - /// - /// Does this group contain the child prim - /// should be able to remove these methods once we have a entity index in scene - /// - /// - /// - public bool HasChildPrim(LLUUID primID) + public void SetOwnerId(LLUUID userId) { - if (m_parts.ContainsKey(primID)) - { - return true; - } - return false; + ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); } - /// - /// Does this group contain the child prim - /// should be able to remove these methods once we have a entity index in scene - /// - /// - /// - public bool HasChildPrim(uint localID) + public void ForEachPart(Action whatToDo) { lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) { - if (part.LocalId == localID) - { - return true; - } + whatToDo(part); } } - return false; } - - #endregion - #region Packet Handlers + #region Events /// - /// Link the prims in a given group to this group + /// /// - /// The group of prims which should be linked to this group - public void LinkToGroup(SceneObjectGroup objectGroup) + public void TriggerTainted() { - if (objectGroup.RootPart.UpdateFlag > 0) + handlerPrimCountTainted = OnPrimCountTainted; + if (handlerPrimCountTainted != null) { - // I've never actually seen this happen, though I think it's theoretically possible - m_log.WarnFormat( - "[SCENE OBJECT GROUP]: Aborted linking {0}, {1} to {2}, {3} as it has yet to finish delinking", - objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); - - return; + handlerPrimCountTainted(); } - -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", -// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); - - SceneObjectPart linkPart = objectGroup.m_rootPart; - - Vector3 oldGroupPosition = - new Vector3(linkPart.GroupPosition.X, linkPart.GroupPosition.Y, linkPart.GroupPosition.Z); - Quaternion oldRootRotation = - new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, linkPart.RotationOffset.Y, - linkPart.RotationOffset.Z); + } - linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; - linkPart.GroupPosition = AbsolutePosition; - Vector3 axPos = new Vector3(linkPart.OffsetPosition.X, linkPart.OffsetPosition.Y, linkPart.OffsetPosition.Z); - - Quaternion parentRot = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - axPos = parentRot.Inverse()*axPos; - - linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); - Quaternion oldRot = - new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, linkPart.RotationOffset.Y, - linkPart.RotationOffset.Z); - Quaternion newRot = parentRot.Inverse()*oldRot; - linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); - - linkPart.ParentID = m_rootPart.LocalId; - - linkPart.LinkNum = m_parts.Count; - - lock (m_parts) + /// + /// Processes backup + /// + /// + public void ProcessBackup(IRegionDataStore datastore) + { + if (HasGroupChanged) { - m_parts.Add(linkPart.UUID, linkPart); + datastore.StoreObject(this, m_scene.RegionInfo.RegionID); + HasGroupChanged = false; } - - linkPart.SetParent(this); - //if (linkPart.PhysActor != null) - //{ - // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); + ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); }); + } - //linkPart.PhysActor = null; - //} + #endregion - //TODO: rest of parts - foreach (SceneObjectPart part in objectGroup.Children.Values) + #region Client Updating + + public void SendFullUpdateToClient(IClientAPI remoteClient, uint clientFlags) + { + lock (m_parts) { - if (part.UUID != objectGroup.m_rootPart.UUID) + foreach (SceneObjectPart part in m_parts.Values) { - LinkNonRootPart(part, oldGroupPosition, oldRootRotation); + SendPartFullUpdate(remoteClient, part, clientFlags); } } + } - DetachFromBackup(objectGroup); + /// + /// Send a full update to the client for the given part + /// + /// + /// + internal void SendPartFullUpdate(IClientAPI remoteClient, SceneObjectPart part, uint clientFlags) + { + if (m_rootPart.UUID == part.UUID) + { + part.SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags); + } + else + { + part.SendFullUpdateToClient(remoteClient, clientFlags); + } + } - m_scene.DeleteEntity(objectGroup.UUID); + /// + /// Send a terse update to the client for the given part + /// + /// + /// + internal void SendPartTerseUpdate(IClientAPI remoteClient, SceneObjectPart part) + { + if (m_rootPart.UUID == part.UUID) + { + part.SendTerseUpdateToClient(remoteClient, AbsolutePosition); + } + else + { + part.SendTerseUpdateToClient(remoteClient); + } + } - // TODO Deleting the parts may cause problems later on if they have already - // made it into the update queue. However, sending out updates for those parts is now - // spurious, so it would be good not to send them at some point. - // The traffic caused is always going to be pretty minor, so it's not high priority - //objectGroup.DeleteParts(); + #endregion - ScheduleGroupForFullUpdate(); - } + #region Copying /// - /// Delink the given prim from this group. The delinked prim is established as - /// an independent SceneObjectGroup. + /// Duplicates this object, including operations such as physics set up and attaching to the backup event. /// - /// - public void DelinkFromGroup(uint partID) - { - SceneObjectPart linkPart = GetChildPart(partID); + /// + public SceneObjectGroup Copy(LLUUID cAgentID, LLUUID cGroupID) + { + SceneObjectGroup dupe = (SceneObjectGroup) MemberwiseClone(); + dupe.m_parts = new Dictionary(); + dupe.m_parts.Clear(); + //dupe.OwnerID = AgentID; + //dupe.GroupID = GroupID; + dupe.AbsolutePosition = new LLVector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); + dupe.m_scene = m_scene; + dupe.m_regionHandle = m_regionHandle; - if (null != linkPart) - { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", -// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); - - LLQuaternion worldRot = linkPart.GetWorldRotation(); - - // Remove the part from this object - lock (m_parts) - { - m_parts.Remove(linkPart.UUID); - } - - linkPart.ParentID = 0; + dupe.CopyRootPart(m_rootPart, OwnerID, GroupID); + dupe.m_rootPart.TrimPermissions(); - if (linkPart.PhysActor != null) - { - m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); - } - - // 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 - = new Quaternion( - m_rootPart.RotationOffset.W, - m_rootPart.RotationOffset.X, - m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - - Vector3 axPos - = new Vector3( - linkPart.OffsetPosition.X, - linkPart.OffsetPosition.Y, - linkPart.OffsetPosition.Z); + /// may need to create a new Physics actor. + if (dupe.RootPart.PhysActor != null) + { + PrimitiveBaseShape pbs = dupe.RootPart.Shape; - axPos = parentRot*axPos; - linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); - linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; - linkPart.OffsetPosition = new LLVector3(0, 0, 0); + dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape( + dupe.RootPart.Name, + pbs, + new PhysicsVector(dupe.RootPart.AbsolutePosition.X, dupe.RootPart.AbsolutePosition.Y, + dupe.RootPart.AbsolutePosition.Z), + new PhysicsVector(dupe.RootPart.Scale.X, dupe.RootPart.Scale.Y, dupe.RootPart.Scale.Z), + new Quaternion(dupe.RootPart.RotationOffset.W, dupe.RootPart.RotationOffset.X, + dupe.RootPart.RotationOffset.Y, dupe.RootPart.RotationOffset.Z), + dupe.RootPart.PhysActor.IsPhysical); - linkPart.RotationOffset = worldRot; + dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId; - // This chunk is probably unnecesary now - delete later on - /* - Quaternion oldRot - = new Quaternion( - linkPart.RotationOffset.W, - linkPart.RotationOffset.X, - linkPart.RotationOffset.Y, - linkPart.RotationOffset.Z); - Quaternion newRot = parentRot*oldRot; - linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); - */ + dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true); + } + // Now we've made a copy that replaces this one, we need to + // switch the owner to the person who did the copying + // Second Life copies an object and duplicates the first one in it's place + // So, we have to make a copy of this one, set it in it's place then set the owner on this one - // Add physics information back to delinked part if appropriate - // XXX This is messy and should be refactorable with the similar section in - // SceneObjectPart.UpdatePrimFlags() - //if (m_rootPart.PhysActor != null) - //{ - //linkPart.PhysActor = m_scene.PhysicsScene.AddPrimShape( - //linkPart.Name, - //linkPart.Shape, - //new PhysicsVector(linkPart.AbsolutePosition.X, linkPart.AbsolutePosition.Y, - //linkPart.AbsolutePosition.Z), - //new PhysicsVector(linkPart.Scale.X, linkPart.Scale.Y, linkPart.Scale.Z), - //new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, - //linkPart.RotationOffset.Y, linkPart.RotationOffset.Z), - //m_rootPart.PhysActor.IsPhysical); - //m_rootPart.DoPhysicsPropertyUpdate(m_rootPart.PhysActor.IsPhysical, true); - //} + SetRootPartOwner(m_rootPart, cAgentID, cGroupID); - SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart); - m_scene.AddEntity(objectGroup); + m_rootPart.ScheduleFullUpdate(); - ScheduleGroupForFullUpdate(); - } - else + List partList = new List(m_parts.Values); + foreach (SceneObjectPart part in partList) { - m_log.InfoFormat("[SCENE OBJECT GROUP]: " + - "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}", - partID, LocalId, UUID); + if (part.UUID != m_rootPart.UUID) + { + dupe.CopyPart(part, OwnerID, GroupID); + SetPartOwner(part, cAgentID, cGroupID); + part.ScheduleFullUpdate(); + } } - } + dupe.UpdateParentIDs(); - private void DetachFromBackup(SceneObjectGroup objectGroup) - { - m_scene.EventManager.OnBackup -= objectGroup.ProcessBackup; + dupe.AttachToBackup(); + ScheduleGroupForFullUpdate(); + + return dupe; } - private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation) + /// + /// + /// + /// + /// + /// + public void CopyRootPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) { - part.SetParent(this); - part.ParentID = m_rootPart.LocalId; - part.LinkNum = m_parts.Count; - + SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); + newPart.SetParent(this); + lock (m_parts) { - m_parts.Add(part.UUID, part); + m_parts.Add(newPart.UUID, newPart); } - Vector3 axiomOldPos = new Vector3(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z); - axiomOldPos = oldGroupRotation*axiomOldPos; - axiomOldPos += oldGroupPosition; - LLVector3 oldAbsolutePosition = new LLVector3(axiomOldPos.x, axiomOldPos.y, axiomOldPos.z); - part.OffsetPosition = oldAbsolutePosition - AbsolutePosition; - - Quaternion axiomRootRotation = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - - Vector3 axiomPos = new Vector3(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z); - axiomPos = axiomRootRotation.Inverse()*axiomPos; - part.OffsetPosition = new LLVector3(axiomPos.x, axiomPos.y, axiomPos.z); + SetPartAsRoot(newPart); + } - Quaternion axiomPartRotation = - new Quaternion(part.RotationOffset.W, part.RotationOffset.X, part.RotationOffset.Y, - part.RotationOffset.Z); + public void ScriptSetPhysicsStatus(bool UsePhysics) + { + if (m_scene.m_physicalPrim) + { + lock (m_parts) + { + foreach (SceneObjectPart part in m_parts.Values) + { + if (UsePhysics) + part.AddFlag(LLObject.ObjectFlags.Physics); + else + part.RemFlag(LLObject.ObjectFlags.Physics); - axiomPartRotation = oldGroupRotation*axiomPartRotation; - axiomPartRotation = axiomRootRotation.Inverse()*axiomPartRotation; - part.RotationOffset = - new LLQuaternion(axiomPartRotation.x, axiomPartRotation.y, axiomPartRotation.z, axiomPartRotation.w); + part.DoPhysicsPropertyUpdate(UsePhysics, false); + IsSelected = false; + } + } + } } - /// - /// If object is physical, apply force to move it around - /// If object is not physical, just put it at the resulting location - /// - /// Always seems to be 0,0,0, so ignoring - /// New position. We do the math here to turn it into a force - /// - public void GrabMovement(LLVector3 offset, LLVector3 pos, IClientAPI remoteClient) + public void ScriptSetPhantomStatus(bool PhantomStatus) { - - if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) + lock (m_parts) { - - if (m_rootPart.PhysActor != null) + foreach (SceneObjectPart part in m_parts.Values) { - if (m_rootPart.PhysActor.IsPhysical) + if (PhantomStatus) { - LLVector3 llmoveforce = pos - AbsolutePosition; - PhysicsVector grabforce = new PhysicsVector(llmoveforce.X, llmoveforce.Y, llmoveforce.Z); - grabforce = (grabforce / 10) * m_rootPart.PhysActor.Mass; - m_rootPart.PhysActor.AddForce(grabforce); - m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + part.AddFlag(LLObject.ObjectFlags.Phantom); + if (part.PhysActor != null) + { + m_scene.PhysicsScene.RemovePrim(part.PhysActor); + } } else { - //NonPhysicalGrabMovement(pos); + part.RemFlag(LLObject.ObjectFlags.Phantom); + if ((part.ObjectFlags & (int) LLObject.ObjectFlags.Physics) != 0) + { + part.DoPhysicsPropertyUpdate(true, false); + } } } - else - { - //NonPhysicalGrabMovement(pos); - } } } - public void NonPhysicalGrabMovement(LLVector3 pos) - { - AbsolutePosition = pos; - m_rootPart.SendTerseUpdateToAllClients(); - } - /// - /// - /// - /// - public void GetProperties(IClientAPI client) + public void applyImpulse(PhysicsVector impulse) { - ObjectPropertiesPacket proper = (ObjectPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - // TODO: don't create new blocks if recycling an old packet - - proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[1]; - proper.ObjectData[0] = new ObjectPropertiesPacket.ObjectDataBlock(); - proper.ObjectData[0].ItemID = LLUUID.Zero; - proper.ObjectData[0].CreationDate = (ulong) m_rootPart.CreationDate; - proper.ObjectData[0].CreatorID = m_rootPart.CreatorID; - proper.ObjectData[0].FolderID = LLUUID.Zero; - proper.ObjectData[0].FromTaskID = LLUUID.Zero; - proper.ObjectData[0].GroupID = LLUUID.Zero; - proper.ObjectData[0].InventorySerial = (short) m_rootPart.InventorySerial; - proper.ObjectData[0].LastOwnerID = m_rootPart.LastOwnerID; - proper.ObjectData[0].ObjectID = UUID; - proper.ObjectData[0].OwnerID = m_rootPart.OwnerID; - proper.ObjectData[0].TouchName = Helpers.StringToField(m_rootPart.TouchName); - proper.ObjectData[0].TextureID = new byte[0]; - proper.ObjectData[0].SitName = Helpers.StringToField(m_rootPart.SitName); - proper.ObjectData[0].Name = Helpers.StringToField(m_rootPart.Name); - proper.ObjectData[0].Description = Helpers.StringToField(m_rootPart.Description); - proper.ObjectData[0].OwnerMask = m_rootPart.OwnerMask; - proper.ObjectData[0].NextOwnerMask = m_rootPart.NextOwnerMask; - proper.ObjectData[0].GroupMask = m_rootPart.GroupMask; - proper.ObjectData[0].EveryoneMask = m_rootPart.EveryoneMask; - proper.ObjectData[0].BaseMask = m_rootPart.BaseMask; - - client.OutPacket(proper, ThrottleOutPacketType.Task); + // 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) + { + rootpart.PhysActor.AddForce(impulse); + m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); + } + } } - /// - /// Set the name of a prim - /// - /// - /// - public void SetPartName(string name, uint localID) + public void moveToTarget(LLVector3 target, float tau) { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + SceneObjectPart rootpart = m_rootPart; + if (rootpart != null) { - part.Name = name; + rootpart.PhysActor.PIDTarget = new PhysicsVector(target.X, target.Y, target.Z); + rootpart.PhysActor.PIDTau = tau; + rootpart.PhysActor.PIDActive = true; } } - public void SetPartDescription(string des, uint localID) + public void stopMoveToTarget() { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + SceneObjectPart rootpart = m_rootPart; + if (rootpart != null) { - part.Description = des; + rootpart.PhysActor.PIDActive = false; } } - public void SetPartText(string text, uint localID) + public void SetRootPartOwner(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + part.LastOwnerID = part.OwnerID; + part.OwnerID = cAgentID; + part.GroupID = cGroupID; + + + if (part.OwnerID != cAgentID) { - part.SetText( text ); - } + // Apply Next Owner Permissions if we're not bypassing permissions + if (!m_scene.PermissionsMngr.BypassPermissions) + m_rootPart.ApplyNextOwnerPermissions(); + } + + part.ScheduleFullUpdate(); } - public void SetPartText(string text, LLUUID partID) + /// + /// + /// + /// + /// + /// + public void CopyPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) { - SceneObjectPart part = GetChildPart(partID); - if (part != null) - { - part.SetText( text ); - } - } + SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); + newPart.SetParent(this); - public string GetPartName(uint localID) - { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + lock (m_parts) { - return part.Name; + m_parts.Add(newPart.UUID, newPart); } - return String.Empty; - } - public string GetPartDescription(uint localID) - { - SceneObjectPart part = GetChildPart(localID); - if (part != null) - { - return part.Description; - } - return String.Empty; + SetPartAsNonRoot(newPart); } /// + /// Reset the LLUUIDs for all the prims that make up this group. /// + /// 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. /// - /// - /// - /// - /// - /// - public void UpdatePrimFlags(uint localID, ushort type, bool inUse, byte[] data) + public void ResetIDs() { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + // As this is only ever called for prims which are not currently part of the scene (and hence + // not accessible by clients), there should be no need to lock + List partsList = new List(m_parts.Values); + m_parts.Clear(); + foreach (SceneObjectPart part in partsList) { - // If we have children - lock (m_parts) - { - if (m_parts.Count > 1) - { - foreach (SceneObjectPart parts in m_parts.Values) - { - parts.UpdatePrimFlags(type, inUse, data); - } - } - else - { - part.UpdatePrimFlags(type, inUse, data); - } - } + part.ResetIDs(m_parts.Count); + m_parts.Add(part.UUID, part); } } - public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) - { - SceneObjectPart part = GetChildPart(localID); - if (part != null) - { - part.UpdateExtraParam(type, inUse, data); - } - } - public SceneObjectPart[] GetParts() - { - int numParts = Children.Count; - SceneObjectPart[] partArray = new SceneObjectPart[numParts]; - Children.Values.CopyTo(partArray, 0); - return partArray; - } - /// /// /// - /// - /// - public void UpdateTextureEntry(uint localID, byte[] textureEntry) + /// + public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, LLUUID AgentID, uint RequestFlags) { - SceneObjectPart part = GetChildPart(localID); - if (part != null) - { - part.UpdateTextureEntry(textureEntry); - } + //RootPart.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags); + ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket) PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + // TODO: don't create new blocks if recycling an old packet + + ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); + objPropDB.RequestFlags = RequestFlags; + objPropDB.ObjectID = RootPart.UUID; + objPropDB.OwnerID = RootPart.ObjectOwner; + objPropDB.GroupID = RootPart.GroupID; + objPropDB.BaseMask = RootPart.BaseMask; + objPropDB.OwnerMask = RootPart.OwnerMask; + objPropDB.GroupMask = RootPart.GroupMask; + objPropDB.EveryoneMask = RootPart.EveryoneMask; + objPropDB.NextOwnerMask = RootPart.NextOwnerMask; + + // TODO: More properties are needed in SceneObjectPart! + objPropDB.OwnershipCost = RootPart.OwnershipCost; + objPropDB.SaleType = RootPart.ObjectSaleType; + objPropDB.SalePrice = RootPart.SalePrice; + objPropDB.Category = RootPart.Category; + objPropDB.LastOwnerID = RootPart.CreatorID; + objPropDB.Name = Helpers.StringToField(RootPart.Name); + objPropDB.Description = Helpers.StringToField(RootPart.Description); + objPropFamilyPack.ObjectData = objPropDB; + remoteClient.OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); } - public void UpdatePermissions(LLUUID AgentID, byte field, uint localID, uint mask, byte addRemTF) + public void SetPartOwner(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) { - SceneObjectPart updatePart = GetChildPart(localID); - updatePart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); - HasGroupChanged = true; + part.OwnerID = cAgentID; + part.GroupID = cGroupID; } #endregion - #region Shape + #region Scheduling /// - /// + /// Examine this object's parts to see if they've changed sufficiently to warrant an update /// - /// - public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID) + public override void Update() { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + lock (m_parts) { - part.UpdateShape(shapeBlock); + if (Util.GetDistanceTo(lastPhysGroupPos, AbsolutePosition) > 0.02) + { + foreach (SceneObjectPart part in m_parts.Values) + { + if (part.UpdateFlag == 0) part.UpdateFlag = 1; + } - if (part.PhysActor != null) - m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); - } - - } + lastPhysGroupPos = AbsolutePosition; + } - #endregion + if ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) + || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) + || (Math.Abs(lastPhysGroupRot.Y - GroupRotation.Y) > 0.1) + || (Math.Abs(lastPhysGroupRot.Z - GroupRotation.Z) > 0.1)) + { + foreach (SceneObjectPart part in m_parts.Values) + { + if (part.UpdateFlag == 0) part.UpdateFlag = 1; + } - #region Resize + lastPhysGroupRot = GroupRotation; + } - /// - /// - /// - /// - /// - public void Resize(LLVector3 scale, uint localID) - { - SceneObjectPart part = GetChildPart(localID); - if (part != null) - { - part.Resize(scale); - if (part.PhysActor != null) + foreach (SceneObjectPart part in m_parts.Values) { - part.PhysActor.Size = - new PhysicsVector(scale.X, scale.Y, scale.Z); - m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); + part.SendScheduledUpdates(); } - //if (part.UUID != m_rootPart.UUID) - ScheduleGroupForFullUpdate(); - - //if (part.UUID == m_rootPart.UUID) - //{ - //if (m_rootPart.PhysActor != null) - //{ - //m_rootPart.PhysActor.Size = - //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z); - //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); - //} - //} } } - public void GroupResize(LLVector3 scale, uint localID) + + public void ScheduleFullUpdateToAvatar(ScenePresence presence) { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + lock (m_parts) { - float x = (scale.X / part.Scale.X); - float y = (scale.Y / part.Scale.Y); - float z = (scale.Z / part.Scale.Z); - part.Resize(scale); - - lock (m_parts) - { - foreach (SceneObjectPart obPart in m_parts.Values) - { - if (obPart.UUID != m_rootPart.UUID) - { - - LLVector3 currentpos = new LLVector3(obPart.OffsetPosition); - currentpos.X *= x; - currentpos.Y *= y; - currentpos.Z *= z; - LLVector3 newSize = new LLVector3(obPart.Scale); - newSize.X *= x; - newSize.Y *= y; - newSize.Z *= z; - obPart.Resize(newSize); - obPart.UpdateOffSet(currentpos); - } - } - } - - if (part.PhysActor != null) + foreach (SceneObjectPart part in m_parts.Values) { - part.PhysActor.Size = - new PhysicsVector(scale.X, scale.Y, scale.Z); - m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); + part.AddFullUpdateToAvatar(presence); } - - - ScheduleGroupForTerseUpdate(); } } - #endregion - - #region Position - - /// - /// - /// - /// - public void UpdateGroupPosition(LLVector3 pos) + public void ScheduleTerseUpdateToAvatar(ScenePresence presence) { - if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) + lock (m_parts) { - AbsolutePosition = pos; + foreach (SceneObjectPart part in m_parts.Values) + { + part.AddTerseUpdateToAvatar(presence); + } } - //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(); } /// - /// + /// Schedule a full update for every part in this object /// - /// - /// - public void UpdateSinglePosition(LLVector3 pos, uint localID) + public void ScheduleGroupForFullUpdate() { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + HasGroupChanged = true; + + lock (m_parts) { - if (part.UUID == m_rootPart.UUID) - { - UpdateRootPosition(pos); - } - else + foreach (SceneObjectPart part in m_parts.Values) { - part.UpdateOffSet(pos); + part.ScheduleFullUpdate(); } } } @@ -1655,579 +1370,864 @@ namespace OpenSim.Region.Environment.Scenes /// /// /// - /// - private void UpdateRootPosition(LLVector3 pos) + public void ScheduleGroupForTerseUpdate() { - LLVector3 newPos = new LLVector3(pos.X, pos.Y, pos.Z); - LLVector3 oldPos = - new LLVector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, - AbsolutePosition.Y + m_rootPart.OffsetPosition.Y, - AbsolutePosition.Z + m_rootPart.OffsetPosition.Z); - LLVector3 diff = oldPos - newPos; - Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z); - Quaternion partRotation = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - axDiff = partRotation.Inverse()*axDiff; - diff.X = axDiff.x; - diff.Y = axDiff.y; - diff.Z = axDiff.z; + HasGroupChanged = true; lock (m_parts) { - foreach (SceneObjectPart obPart in m_parts.Values) + foreach (SceneObjectPart part in m_parts.Values) { - if (obPart.UUID != m_rootPart.UUID) - { - obPart.OffsetPosition = obPart.OffsetPosition + diff; - } + part.ScheduleTerseUpdate(); } } - - AbsolutePosition = newPos; - ScheduleGroupForTerseUpdate(); } - public void OffsetForNewRegion(LLVector3 offset) + /// + /// + /// + public void SendGroupFullUpdate() { - m_rootPart.GroupPosition = offset; + HasGroupChanged = true; + + lock (m_parts) + { + foreach (SceneObjectPart part in m_parts.Values) + { + part.SendFullUpdateToAllClients(); + } + } + } + + public void QueueForUpdateCheck() + { + m_scene.m_innerScene.AddToUpdateList(this); + } + + /// + /// + /// + public void SendGroupTerseUpdate() + { + HasGroupChanged = true; + + lock (m_parts) + { + foreach (SceneObjectPart part in m_parts.Values) + { + part.SendTerseUpdateToAllClients(); + } + } } #endregion - #region Rotation + #region SceneGroupPart Methods /// - /// + /// Get the child part by LinkNum /// - /// - public void UpdateGroupRotation(LLQuaternion rot) + /// + /// null if no child part with that linknum or child part + public SceneObjectPart GetLinkNumPart(int linknum) { - m_rootPart.UpdateRotation(rot); - if (m_rootPart.PhysActor != null) + lock (m_parts) { - m_rootPart.PhysActor.Orientation = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + foreach (SceneObjectPart part in m_parts.Values) + { + if (part.LinkNum == linknum) + { + return part; + } + } } - ScheduleGroupForTerseUpdate(); + + return null; } /// - /// + /// Get a child part with a given UUID /// - /// - /// - public void UpdateGroupRotation(LLVector3 pos, LLQuaternion rot) + /// + /// null if a child part with the primID was not found + public SceneObjectPart GetChildPart(LLUUID primID) { - m_rootPart.UpdateRotation(rot); - if (m_rootPart.PhysActor != null) + SceneObjectPart childPart = null; + if (m_parts.ContainsKey(primID)) { - m_rootPart.PhysActor.Orientation = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + childPart = m_parts[primID]; } - AbsolutePosition = pos; - ScheduleGroupForTerseUpdate(); + return childPart; } /// - /// + /// Get a child part with a given local ID /// - /// /// - public void UpdateSingleRotation(LLQuaternion rot, uint localID) + /// null if a child part with the local ID was not found + public SceneObjectPart GetChildPart(uint localID) { - SceneObjectPart part = GetChildPart(localID); - if (part != null) + lock (m_parts) { - if (part.UUID == m_rootPart.UUID) - { - UpdateRootRotation(rot); - } - else + foreach (SceneObjectPart part in m_parts.Values) { - part.UpdateRotation(rot); + if (part.LocalId == localID) + { + return part; + } } } + + return null; } /// - /// + /// Does this group contain the child prim + /// should be able to remove these methods once we have a entity index in scene /// - /// - private void UpdateRootRotation(LLQuaternion rot) + /// + /// + public bool HasChildPrim(LLUUID primID) { - Quaternion axRot = new Quaternion(rot.W, rot.X, rot.Y, rot.Z); - Quaternion oldParentRot = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - - m_rootPart.UpdateRotation(rot); - if (m_rootPart.PhysActor != null) + if (m_parts.ContainsKey(primID)) { - m_rootPart.PhysActor.Orientation = - new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, - m_rootPart.RotationOffset.Z); - m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + return true; } + return false; + } + /// + /// Does this group contain the child prim + /// should be able to remove these methods once we have a entity index in scene + /// + /// + /// + public bool HasChildPrim(uint localID) + { lock (m_parts) { - foreach (SceneObjectPart prim in m_parts.Values) + foreach (SceneObjectPart part in m_parts.Values) { - if (prim.UUID != m_rootPart.UUID) + if (part.LocalId == localID) { - Vector3 axPos = new Vector3(prim.OffsetPosition.X, prim.OffsetPosition.Y, prim.OffsetPosition.Z); - axPos = oldParentRot*axPos; - axPos = axRot.Inverse()*axPos; - prim.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); - Quaternion primsRot = - new Quaternion(prim.RotationOffset.W, prim.RotationOffset.X, prim.RotationOffset.Y, - prim.RotationOffset.Z); - Quaternion newRot = oldParentRot*primsRot; - newRot = axRot.Inverse()*newRot; - prim.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); - prim.ScheduleTerseUpdate(); + return true; } } } - - m_rootPart.ScheduleTerseUpdate(); + return false; } #endregion + #region Packet Handlers + /// - /// + /// Link the prims in a given group to this group /// - /// - private void SetPartAsRoot(SceneObjectPart part) + /// The group of prims which should be linked to this group + public void LinkToGroup(SceneObjectGroup objectGroup) { - m_rootPart = part; + if (objectGroup.RootPart.UpdateFlag > 0) + { + // I've never actually seen this happen, though I think it's theoretically possible + m_log.WarnFormat( + "[SCENE OBJECT GROUP]: Aborted linking {0}, {1} to {2}, {3} as it has yet to finish delinking", + objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); + + return; + } + +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", +// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); + + SceneObjectPart linkPart = objectGroup.m_rootPart; + + Vector3 oldGroupPosition = + new Vector3(linkPart.GroupPosition.X, linkPart.GroupPosition.Y, linkPart.GroupPosition.Z); + Quaternion oldRootRotation = + new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, linkPart.RotationOffset.Y, + linkPart.RotationOffset.Z); + + linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; + linkPart.GroupPosition = AbsolutePosition; + Vector3 axPos = new Vector3(linkPart.OffsetPosition.X, linkPart.OffsetPosition.Y, linkPart.OffsetPosition.Z); + + Quaternion parentRot = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + axPos = parentRot.Inverse() * axPos; + + linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); + Quaternion oldRot = + new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, linkPart.RotationOffset.Y, + linkPart.RotationOffset.Z); + Quaternion newRot = parentRot.Inverse() * oldRot; + linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); + + linkPart.ParentID = m_rootPart.LocalId; + + linkPart.LinkNum = m_parts.Count; + + lock (m_parts) + { + m_parts.Add(linkPart.UUID, linkPart); + } + + linkPart.SetParent(this); + + //if (linkPart.PhysActor != null) + //{ + // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); + + //linkPart.PhysActor = null; + //} + + //TODO: rest of parts + foreach (SceneObjectPart part in objectGroup.Children.Values) + { + if (part.UUID != objectGroup.m_rootPart.UUID) + { + LinkNonRootPart(part, oldGroupPosition, oldRootRotation); + } + } + + DetachFromBackup(objectGroup); + + m_scene.DeleteEntity(objectGroup.UUID); + + // TODO Deleting the parts may cause problems later on if they have already + // made it into the update queue. However, sending out updates for those parts is now + // spurious, so it would be good not to send them at some point. + // The traffic caused is always going to be pretty minor, so it's not high priority + //objectGroup.DeleteParts(); + + ScheduleGroupForFullUpdate(); } /// - /// + /// Delink the given prim from this group. The delinked prim is established as + /// an independent SceneObjectGroup. /// - /// - private void SetPartAsNonRoot(SceneObjectPart part) + /// + public void DelinkFromGroup(uint partID) + { + SceneObjectPart linkPart = GetChildPart(partID); + + if (null != linkPart) + { +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", +// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); + + LLQuaternion worldRot = linkPart.GetWorldRotation(); + + // Remove the part from this object + lock (m_parts) + { + m_parts.Remove(linkPart.UUID); + } + + linkPart.ParentID = 0; + + if (linkPart.PhysActor != null) + { + m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); + } + + // 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 + = new Quaternion( + m_rootPart.RotationOffset.W, + m_rootPart.RotationOffset.X, + m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + + Vector3 axPos + = new Vector3( + linkPart.OffsetPosition.X, + linkPart.OffsetPosition.Y, + linkPart.OffsetPosition.Z); + + axPos = parentRot * axPos; + linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); + linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; + linkPart.OffsetPosition = new LLVector3(0, 0, 0); + + linkPart.RotationOffset = worldRot; + + // This chunk is probably unnecesary now - delete later on + /* + Quaternion oldRot + = new Quaternion( + linkPart.RotationOffset.W, + linkPart.RotationOffset.X, + linkPart.RotationOffset.Y, + linkPart.RotationOffset.Z); + Quaternion newRot = parentRot*oldRot; + linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); + */ + + // Add physics information back to delinked part if appropriate + // XXX This is messy and should be refactorable with the similar section in + // SceneObjectPart.UpdatePrimFlags() + //if (m_rootPart.PhysActor != null) + //{ + //linkPart.PhysActor = m_scene.PhysicsScene.AddPrimShape( + //linkPart.Name, + //linkPart.Shape, + //new PhysicsVector(linkPart.AbsolutePosition.X, linkPart.AbsolutePosition.Y, + //linkPart.AbsolutePosition.Z), + //new PhysicsVector(linkPart.Scale.X, linkPart.Scale.Y, linkPart.Scale.Z), + //new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, + //linkPart.RotationOffset.Y, linkPart.RotationOffset.Z), + //m_rootPart.PhysActor.IsPhysical); + //m_rootPart.DoPhysicsPropertyUpdate(m_rootPart.PhysActor.IsPhysical, true); + //} + + SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart); + + m_scene.AddEntity(objectGroup); + + ScheduleGroupForFullUpdate(); + } + else + { + m_log.InfoFormat("[SCENE OBJECT GROUP]: " + + "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}", + partID, LocalId, UUID); + } + } + + private void DetachFromBackup(SceneObjectGroup objectGroup) { + m_scene.EventManager.OnBackup -= objectGroup.ProcessBackup; + } + + private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation) + { + part.SetParent(this); part.ParentID = m_rootPart.LocalId; + part.LinkNum = m_parts.Count; + + lock (m_parts) + { + m_parts.Add(part.UUID, part); + } + + Vector3 axiomOldPos = new Vector3(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z); + axiomOldPos = oldGroupRotation * axiomOldPos; + axiomOldPos += oldGroupPosition; + LLVector3 oldAbsolutePosition = new LLVector3(axiomOldPos.x, axiomOldPos.y, axiomOldPos.z); + part.OffsetPosition = oldAbsolutePosition - AbsolutePosition; + + Quaternion axiomRootRotation = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + + Vector3 axiomPos = new Vector3(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z); + axiomPos = axiomRootRotation.Inverse() * axiomPos; + part.OffsetPosition = new LLVector3(axiomPos.x, axiomPos.y, axiomPos.z); + + Quaternion axiomPartRotation = + new Quaternion(part.RotationOffset.W, part.RotationOffset.X, part.RotationOffset.Y, + part.RotationOffset.Z); + + axiomPartRotation = oldGroupRotation * axiomPartRotation; + axiomPartRotation = axiomRootRotation.Inverse() * axiomPartRotation; + part.RotationOffset = + new LLQuaternion(axiomPartRotation.x, axiomPartRotation.y, axiomPartRotation.z, axiomPartRotation.w); } /// - /// + /// If object is physical, apply force to move it around + /// If object is not physical, just put it at the resulting location /// - /// - public List GetScenePresences() + /// Always seems to be 0,0,0, so ignoring + /// New position. We do the math here to turn it into a force + /// + public void GrabMovement(LLVector3 offset, LLVector3 pos, IClientAPI remoteClient) { - return m_scene.GetScenePresences(); + if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) + { + if (m_rootPart.PhysActor != null) + { + if (m_rootPart.PhysActor.IsPhysical) + { + LLVector3 llmoveforce = pos - AbsolutePosition; + PhysicsVector grabforce = new PhysicsVector(llmoveforce.X, llmoveforce.Y, llmoveforce.Z); + grabforce = (grabforce / 10) * m_rootPart.PhysActor.Mass; + m_rootPart.PhysActor.AddForce(grabforce); + m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + } + else + { + //NonPhysicalGrabMovement(pos); + } + } + else + { + //NonPhysicalGrabMovement(pos); + } + } } - #region Events + public void NonPhysicalGrabMovement(LLVector3 pos) + { + AbsolutePosition = pos; + m_rootPart.SendTerseUpdateToAllClients(); + } /// /// /// - public void TriggerTainted() + /// + public void GetProperties(IClientAPI client) { - handlerPrimCountTainted = OnPrimCountTainted; - if (handlerPrimCountTainted != null) - { - handlerPrimCountTainted(); - } + ObjectPropertiesPacket proper = (ObjectPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + // TODO: don't create new blocks if recycling an old packet + + proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[1]; + proper.ObjectData[0] = new ObjectPropertiesPacket.ObjectDataBlock(); + proper.ObjectData[0].ItemID = LLUUID.Zero; + proper.ObjectData[0].CreationDate = (ulong) m_rootPart.CreationDate; + proper.ObjectData[0].CreatorID = m_rootPart.CreatorID; + proper.ObjectData[0].FolderID = LLUUID.Zero; + proper.ObjectData[0].FromTaskID = LLUUID.Zero; + proper.ObjectData[0].GroupID = LLUUID.Zero; + proper.ObjectData[0].InventorySerial = (short) m_rootPart.InventorySerial; + proper.ObjectData[0].LastOwnerID = m_rootPart.LastOwnerID; + proper.ObjectData[0].ObjectID = UUID; + proper.ObjectData[0].OwnerID = m_rootPart.OwnerID; + proper.ObjectData[0].TouchName = Helpers.StringToField(m_rootPart.TouchName); + proper.ObjectData[0].TextureID = new byte[0]; + proper.ObjectData[0].SitName = Helpers.StringToField(m_rootPart.SitName); + proper.ObjectData[0].Name = Helpers.StringToField(m_rootPart.Name); + proper.ObjectData[0].Description = Helpers.StringToField(m_rootPart.Description); + proper.ObjectData[0].OwnerMask = m_rootPart.OwnerMask; + proper.ObjectData[0].NextOwnerMask = m_rootPart.NextOwnerMask; + proper.ObjectData[0].GroupMask = m_rootPart.GroupMask; + proper.ObjectData[0].EveryoneMask = m_rootPart.EveryoneMask; + proper.ObjectData[0].BaseMask = m_rootPart.BaseMask; + + client.OutPacket(proper, ThrottleOutPacketType.Task); } /// - /// Processes backup + /// Set the name of a prim /// - /// - public void ProcessBackup(IRegionDataStore datastore) + /// + /// + public void SetPartName(string name, uint localID) { - if (HasGroupChanged) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - datastore.StoreObject(this, m_scene.RegionInfo.RegionID); - HasGroupChanged = false; + part.Name = name; } - - ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); }); } - #endregion - - #region Client Updating - - public void SendFullUpdateToClient(IClientAPI remoteClient, uint clientFlags) + public void SetPartDescription(string des, uint localID) { - lock (m_parts) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - foreach (SceneObjectPart part in m_parts.Values) - { - SendPartFullUpdate(remoteClient, part, clientFlags); - } + part.Description = des; } } - /// - /// Send a full update to the client for the given part - /// - /// - /// - internal void SendPartFullUpdate(IClientAPI remoteClient, SceneObjectPart part, uint clientFlags) + public void SetPartText(string text, uint localID) { - if (m_rootPart.UUID == part.UUID) - { - part.SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags); - } - else + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - part.SendFullUpdateToClient(remoteClient, clientFlags); + part.SetText(text); } } - /// - /// Send a terse update to the client for the given part - /// - /// - /// - internal void SendPartTerseUpdate(IClientAPI remoteClient, SceneObjectPart part) + public void SetPartText(string text, LLUUID partID) { - if (m_rootPart.UUID == part.UUID) - { - part.SendTerseUpdateToClient(remoteClient, AbsolutePosition); - } - else + SceneObjectPart part = GetChildPart(partID); + if (part != null) { - part.SendTerseUpdateToClient(remoteClient); + part.SetText(text); } } - #endregion - - public override void UpdateMovement() + public string GetPartName(uint localID) { - lock (m_parts) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - foreach (SceneObjectPart part in m_parts.Values) - { - part.UpdateMovement(); - } + return part.Name; } - } - - public float GetTimeDilation() - { - return m_scene.TimeDilation; - } - - /// - /// Added as a way for the storage provider to reset the scene, - /// most likely a better way to do this sort of thing but for now... - /// - /// - public void SetScene(Scene scene) - { - m_scene = scene; - AttachToBackup(); + return String.Empty; } - /// - /// - /// - /// - public void AddPart(SceneObjectPart part) + public string GetPartDescription(uint localID) { - lock (m_parts) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - part.SetParent(this); - part.LinkNum = m_parts.Count; - - try - { - m_parts.Add(part.UUID, part); - } - catch (Exception e) - { - m_log.Error("Failed to add scened object part", e); - } + return part.Description; } + return String.Empty; } /// /// /// - public void UpdateParentIDs() + /// + /// + /// + /// + /// + public void UpdatePrimFlags(uint localID, ushort type, bool inUse, byte[] data) { - lock (m_parts) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - foreach (SceneObjectPart part in m_parts.Values) + // If we have children + lock (m_parts) { - if (part.UUID != m_rootPart.UUID) + if (m_parts.Count > 1) { - part.ParentID = m_rootPart.LocalId; + foreach (SceneObjectPart parts in m_parts.Values) + { + parts.UpdatePrimFlags(type, inUse, data); + } + } + else + { + part.UpdatePrimFlags(type, inUse, data); } } } } - public void RegenerateFullIDs() + public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) { - lock (m_parts) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - foreach (SceneObjectPart part in m_parts.Values) - { - part.UUID = LLUUID.Random(); - } + part.UpdateExtraParam(type, inUse, data); } } - public void ResetChildPrimPhysicsPositions() + public SceneObjectPart[] GetParts() { - AbsolutePosition = AbsolutePosition; - HasGroupChanged = false; + int numParts = Children.Count; + SceneObjectPart[] partArray = new SceneObjectPart[numParts]; + Children.Values.CopyTo(partArray, 0); + return partArray; } - public LLUUID GetPartsFullID(uint localID) + /// + /// + /// + /// + /// + public void UpdateTextureEntry(uint localID, byte[] textureEntry) { SceneObjectPart part = GetChildPart(localID); if (part != null) { - return part.UUID; + part.UpdateTextureEntry(textureEntry); } - return null; } - public void ObjectGrabHandler(uint localId, LLVector3 offsetPos, IClientAPI remoteClient) + public void UpdatePermissions(LLUUID AgentID, byte field, uint localID, uint mask, byte addRemTF) { - if (m_rootPart.LocalId == localId) - { - OnGrabGroup(offsetPos, remoteClient); - } - else - { - SceneObjectPart part = GetChildPart(localId); - OnGrabPart(part, offsetPos, remoteClient); - } + SceneObjectPart updatePart = GetChildPart(localID); + updatePart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); + HasGroupChanged = true; } - public virtual void OnGrabPart(SceneObjectPart part, LLVector3 offsetPos, IClientAPI remoteClient) - { - part.OnGrab(offsetPos, remoteClient); - } + #endregion - public virtual void OnGrabGroup(LLVector3 offsetPos, IClientAPI remoteClient) + #region Shape + + /// + /// + /// + /// + public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID) { - m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId); + SceneObjectPart part = GetChildPart(localID); + if (part != null) + { + part.UpdateShape(shapeBlock); + + if (part.PhysActor != null) + m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); + } } + #endregion + + #region Resize + /// - /// Completely delete this group and tell all the scene presences about that deletion. + /// /// - public void DeleteGroup() - { - DetachFromBackup(this); - - lock (m_parts) + /// + /// + public void Resize(LLVector3 scale, uint localID) + { + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - foreach (SceneObjectPart part in m_parts.Values) + part.Resize(scale); + if (part.PhysActor != null) { - List avatars = GetScenePresences(); - for (int i = 0; i < avatars.Count; i++) + part.PhysActor.Size = + new PhysicsVector(scale.X, scale.Y, scale.Z); + m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); + } + //if (part.UUID != m_rootPart.UUID) + ScheduleGroupForFullUpdate(); + + //if (part.UUID == m_rootPart.UUID) + //{ + //if (m_rootPart.PhysActor != null) + //{ + //m_rootPart.PhysActor.Size = + //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z); + //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + //} + //} + } + } + + public void GroupResize(LLVector3 scale, uint localID) + { + SceneObjectPart part = GetChildPart(localID); + if (part != null) + { + float x = (scale.X / part.Scale.X); + float y = (scale.Y / part.Scale.Y); + float z = (scale.Z / part.Scale.Z); + part.Resize(scale); + + lock (m_parts) + { + foreach (SceneObjectPart obPart in m_parts.Values) { - if (avatars[i].ParentID == LocalId) + if (obPart.UUID != m_rootPart.UUID) { - avatars[i].StandUp(); + LLVector3 currentpos = new LLVector3(obPart.OffsetPosition); + currentpos.X *= x; + currentpos.Y *= y; + currentpos.Z *= z; + LLVector3 newSize = new LLVector3(obPart.Scale); + newSize.X *= x; + newSize.Y *= y; + newSize.Z *= z; + obPart.Resize(newSize); + obPart.UpdateOffSet(currentpos); } - - avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); } } - } - } - /// - /// Delete all the parts in this group. - /// - public void DeleteParts() - { - lock (m_parts) - { - foreach (SceneObjectPart part in m_parts.Values) + if (part.PhysActor != null) { - part.StopScripts(); + part.PhysActor.Size = + new PhysicsVector(scale.X, scale.Y, scale.Z); + m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); } - - m_rootPart = null; - m_parts.Clear(); + + + ScheduleGroupForTerseUpdate(); } } - public void AddScriptLPS(int count) - { - InnerScene d = m_scene.m_innerScene; - d.AddToScriptLPS(count); - } + #endregion - public void AddActiveScriptCount(int count) - { - InnerScene d = m_scene.m_innerScene; - d.AddActiveScripts(count); - } + #region Position - public void RemoveScriptEvents(LLUUID scriptid) + /// + /// + /// + /// + public void UpdateGroupPosition(LLVector3 pos) { - lock (m_scriptEvents) + if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) { - if (m_scriptEvents.ContainsKey(scriptid)) - { - scriptEvents oldparts = scriptEvents.None; - oldparts = (scriptEvents)m_scriptEvents[scriptid]; - - // remove values from aggregated script events - m_aggregateScriptEvents &= ~oldparts; - m_scriptEvents.Remove(scriptid); - } - + AbsolutePosition = pos; } - aggregateScriptEvents(); + //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(); } - public void SetScriptEvents(LLUUID scriptid, int events) + /// + /// + /// + /// + /// + public void UpdateSinglePosition(LLVector3 pos, uint localID) { - - scriptEvents oldparts = scriptEvents.None; - lock (m_scriptEvents) + SceneObjectPart part = GetChildPart(localID); + if (part != null) { - if (m_scriptEvents.ContainsKey(scriptid)) + if (part.UUID == m_rootPart.UUID) { - oldparts = (scriptEvents)m_scriptEvents[scriptid]; - - // remove values from aggregated script events - m_aggregateScriptEvents &= ~oldparts; - m_scriptEvents[scriptid] = (scriptEvents)events; + UpdateRootPosition(pos); } else { - m_scriptEvents.Add(scriptid, (scriptEvents)events); + part.UpdateOffSet(pos); } - } - - aggregateScriptEvents(); } - public void aggregateScriptEvents() + + /// + /// + /// + /// + private void UpdateRootPosition(LLVector3 pos) { - // Aggregate script events - lock (m_scriptEvents) + LLVector3 newPos = new LLVector3(pos.X, pos.Y, pos.Z); + LLVector3 oldPos = + new LLVector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, + AbsolutePosition.Y + m_rootPart.OffsetPosition.Y, + AbsolutePosition.Z + m_rootPart.OffsetPosition.Z); + LLVector3 diff = oldPos - newPos; + Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z); + Quaternion partRotation = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + axDiff = partRotation.Inverse() * axDiff; + diff.X = axDiff.x; + diff.Y = axDiff.y; + diff.Z = axDiff.z; + + lock (m_parts) { - foreach (scriptEvents s in m_scriptEvents.Values) + foreach (SceneObjectPart obPart in m_parts.Values) { - m_aggregateScriptEvents |= s; + if (obPart.UUID != m_rootPart.UUID) + { + obPart.OffsetPosition = obPart.OffsetPosition + diff; + } } } - uint objectflagupdate = m_rootPart.ObjectFlags; - if ( - ((m_aggregateScriptEvents & scriptEvents.touch) != 0) || - ((m_aggregateScriptEvents & scriptEvents.touch_end) != 0) || - ((m_aggregateScriptEvents & scriptEvents.touch_start) != 0) - ) - { - objectflagupdate |= (uint)LLObject.ObjectFlags.Touch; - } - else - { - objectflagupdate &= ~(uint)LLObject.ObjectFlags.Touch; - } + AbsolutePosition = newPos; + ScheduleGroupForTerseUpdate(); + } - if ((m_aggregateScriptEvents & scriptEvents.money) != 0) - { - objectflagupdate |= (uint)LLObject.ObjectFlags.Money; - } - else - { - objectflagupdate &= ~(uint)LLObject.ObjectFlags.Money; - } + public void OffsetForNewRegion(LLVector3 offset) + { + m_rootPart.GroupPosition = offset; + } - if ( - ((m_aggregateScriptEvents & scriptEvents.collision) != 0) || - ((m_aggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((m_aggregateScriptEvents & scriptEvents.collision_start) != 0) - ) - { - // subscribe to physics updates. - } - else - { - // unsubscribe to physics updates. - } - lock (m_parts) + #endregion + + #region Rotation + + /// + /// + /// + /// + public void UpdateGroupRotation(LLQuaternion rot) + { + m_rootPart.UpdateRotation(rot); + if (m_rootPart.PhysActor != null) { - foreach (SceneObjectPart part in m_parts.Values) - { - part.ObjectFlags = objectflagupdate; - } + m_rootPart.PhysActor.Orientation = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); } - ScheduleGroupForFullUpdate(); - + ScheduleGroupForTerseUpdate(); } - public override void SetText(string text, Vector3 color, double alpha) + /// + /// + /// + /// + /// + public void UpdateGroupRotation(LLVector3 pos, LLQuaternion rot) { - Color = Color.FromArgb(0xff - (int) (alpha*0xff), - (int) (color.x*0xff), - (int) (color.y*0xff), - (int) (color.z*0xff)); - Text = text; - - m_rootPart.ScheduleFullUpdate(); + m_rootPart.UpdateRotation(rot); + if (m_rootPart.PhysActor != null) + { + m_rootPart.PhysActor.Orientation = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + } + AbsolutePosition = pos; + ScheduleGroupForTerseUpdate(); } - public void ApplyPhysics(bool m_physicalPrim) + /// + /// + /// + /// + /// + public void UpdateSingleRotation(LLQuaternion rot, uint localID) { - lock (m_parts) - { - if (m_parts.Count > 1) + SceneObjectPart part = GetChildPart(localID); + if (part != null) + { + if (part.UUID == m_rootPart.UUID) { - m_rootPart.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); - foreach (SceneObjectPart part in m_parts.Values) - { - if (part.LocalId != m_rootPart.LocalId) - { - part.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); - } - // Hack to get the physics scene geometries in the right spot - ResetChildPrimPhysicsPositions(); - - } + UpdateRootRotation(rot); } else { - m_rootPart.ApplyPhysics(m_rootPart.ObjectFlags, m_physicalPrim); - } + part.UpdateRotation(rot); + } } } - public void SetOwnerId(LLUUID userId) + /// + /// + /// + /// + private void UpdateRootRotation(LLQuaternion rot) { - ForEachPart(delegate(SceneObjectPart part) - { part.OwnerID = userId; }); - } + Quaternion axRot = new Quaternion(rot.W, rot.X, rot.Y, rot.Z); + Quaternion oldParentRot = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + + m_rootPart.UpdateRotation(rot); + if (m_rootPart.PhysActor != null) + { + m_rootPart.PhysActor.Orientation = + new Quaternion(m_rootPart.RotationOffset.W, m_rootPart.RotationOffset.X, m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + } - public void ForEachPart(Action whatToDo) - { lock (m_parts) { - foreach (SceneObjectPart part in m_parts.Values) + foreach (SceneObjectPart prim in m_parts.Values) { - whatToDo(part); + if (prim.UUID != m_rootPart.UUID) + { + Vector3 axPos = new Vector3(prim.OffsetPosition.X, prim.OffsetPosition.Y, prim.OffsetPosition.Z); + axPos = oldParentRot * axPos; + axPos = axRot.Inverse() * axPos; + prim.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); + Quaternion primsRot = + new Quaternion(prim.RotationOffset.W, prim.RotationOffset.X, prim.RotationOffset.Y, + prim.RotationOffset.Z); + Quaternion newRot = oldParentRot * primsRot; + newRot = axRot.Inverse() * newRot; + prim.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); + prim.ScheduleTerseUpdate(); + } } } + + m_rootPart.ScheduleTerseUpdate(); } - + #endregion } -} +} \ No newline at end of file -- cgit v1.1