diff --git a/OpenSim/Region/Environment/Scenes/SceneGraph.cs b/OpenSim/Region/Environment/Scenes/SceneGraph.cs index b373c09afd..d261e2de06 100644 --- a/OpenSim/Region/Environment/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Environment/Scenes/SceneGraph.cs @@ -1203,6 +1203,8 @@ namespace OpenSim.Region.Environment.Scenes /// /// /// + /// This routine seems to get called when a user changes object settings in the viewer. + /// If some one can confirm that, please change the comment according. protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient) { SceneObjectGroup group = GetGroupByPrim(localID); @@ -1210,7 +1212,7 @@ namespace OpenSim.Region.Environment.Scenes { if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) { - group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom); + group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom, false); // VolumeDetect can't be set via UI and will always be off when a change is made there } } } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index 545628256b..f4ccc46648 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -1431,21 +1431,45 @@ namespace OpenSim.Region.Environment.Scenes { bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0); bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0); - UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom); + bool IsVolumeDetect = RootPart.VolumeDetectActive; + UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); } public void ScriptSetTemporaryStatus(bool TemporaryStatus) { bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0); - UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom); + bool IsVolumeDetect = RootPart.VolumeDetectActive; + UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect); } public void ScriptSetPhantomStatus(bool PhantomStatus) { bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0); - UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus); + 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(); + */ } public void applyImpulse(PhysicsVector impulse) @@ -2251,7 +2275,7 @@ namespace OpenSim.Region.Environment.Scenes /// /// /// - public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom) + public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect) { SceneObjectPart selectionPart = GetChildPart(localID); @@ -2279,7 +2303,7 @@ namespace OpenSim.Region.Environment.Scenes foreach (SceneObjectPart part in m_parts.Values) { - part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom); + part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); } } } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 6b4d47a08b..0315c929b9 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -167,7 +167,11 @@ namespace OpenSim.Region.Environment.Scenes [XmlIgnore] public PhysicsVector RotationAxis = new PhysicsVector(1f,1f,1f); - + + [XmlIgnore] + public bool VolumeDetectActive = false; // XmlIgnore set to avoid problems with persistance until I come to care for this + // Certainly this must be a persistant setting finally + /// /// This part's inventory /// @@ -2178,6 +2182,16 @@ if (m_shape != null) { m_parentGroup.ScriptSetPhysicsStatus(UsePhysics); } + public void ScriptSetVolumeDetect(bool SetVD) + { + + if (m_parentGroup != null) + { + m_parentGroup.ScriptSetVolumeDetect(SetVD); + } + } + + public void SculptTextureCallback(UUID textureID, AssetBase texture) { if (m_shape.SculptEntry) @@ -2484,14 +2498,6 @@ if (m_shape != null) { } } - public void SetVolumeDetect(int param) - { - if (PhysActor != null) - { - PhysActor.SetVolumeDetect(param); - } - } - public void SetGroup(UUID groupID, IClientAPI client) { _groupID = groupID; @@ -3184,17 +3190,46 @@ if (m_shape != null) { } } - public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom) + public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) { bool wasUsingPhysics = ((ObjectFlags & (uint) PrimFlags.Physics) != 0); bool wasTemporary = ((ObjectFlags & (uint)PrimFlags.TemporaryOnRez) != 0); bool wasPhantom = ((ObjectFlags & (uint)PrimFlags.Phantom) != 0); + bool wasVD = VolumeDetectActive; - if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom)) + if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom) && (IsVD==wasVD) ) { return; } + // Special cases for VD. VD can only be called from a script + // and can't be combined with changes to other states. So we can rely + // that... + // ... if VD is changed, all others are not. + // ... if one of the others is changed, VD is not. + if (IsVD) // VD is active, special logic applies + { + // State machine logic for VolumeDetect + // More logic below + bool phanReset = (IsPhantom != wasPhantom) && !IsPhantom; + + if (phanReset) // Phantom changes from on to off switch VD off too + { + IsVD = false; // Switch it of for the course of this routine + VolumeDetectActive = false; // and also permanently + if (PhysActor != null) + PhysActor.SetVolumeDetect(0); // Let physics know about it too + } + else + { + IsPhantom = false; + // If volumedetect is active we don't want phantom to be applied. + // If this is a new call to VD out of the state "phantom" + // this will also cause the prim to be visible to physics + } + + } + if (UsePhysics) { AddFlag(PrimFlags.Physics); @@ -3222,6 +3257,7 @@ if (m_shape != null) { } } + if (IsPhantom || IsAttachment) { AddFlag(PrimFlags.Phantom); @@ -3232,11 +3268,13 @@ if (m_shape != null) { PhysActor = null; } } - else + else // Not phantom { RemFlag(PrimFlags.Phantom); + if (PhysActor == null) { + // It's not phantom anymore. So make sure the physics engine get's knowledge of it PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( Name, Shape, @@ -3261,10 +3299,11 @@ if (m_shape != null) { } } } - else + else // it already has a physical representation { - PhysActor.IsPhysical = UsePhysics; - DoPhysicsPropertyUpdate(UsePhysics, false); + PhysActor.IsPhysical = UsePhysics; + + DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim if (m_parentGroup != null) { if (!m_parentGroup.IsDeleted) @@ -3278,6 +3317,32 @@ if (m_shape != null) { } } + if (IsVD) + { + // If the above logic worked (this is urgent candidate to unit tests!) + // we now have a physicsactor. + // Defensive programming calls for a check here. + // Better would be throwing an exception that could be catched by a unit test as the internal + // logic should make sure, this Physactor is always here. + if (this.PhysActor != null) + { + PhysActor.SetVolumeDetect(1); + AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active + this.VolumeDetectActive = true; + } + + } + else + { // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like + // (mumbles, well, at least if you have infinte CPU powers :-) ) + if (this.PhysActor != null) + { + PhysActor.SetVolumeDetect(0); + } + this.VolumeDetectActive = false; + } + + if (IsTemporary) { AddFlag(PrimFlags.TemporaryOnRez); @@ -3287,6 +3352,7 @@ if (m_shape != null) { RemFlag(PrimFlags.TemporaryOnRez); } // System.Console.WriteLine("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); + ParentGroup.HasGroupChanged = true; ScheduleFullUpdate(); } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 6f5abfa6a6..b9c0936953 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -127,6 +127,8 @@ namespace OpenSim.Region.Physics.OdePlugin private bool m_isphysical = false; private bool m_isSelected = false; + internal bool m_isVolumeDetect = false; // If true, this prim only detects collisions but doesn't collide actively + private bool m_throttleUpdates = false; private int throttleCounter = 0; public int m_interpenetrationcount = 0; @@ -2226,7 +2228,10 @@ namespace OpenSim.Region.Physics.OdePlugin public override void SetVolumeDetect(int param) { - + lock (_parent_scene.OdeLock) + { + m_isVolumeDetect = (param!=0); + } } public override PhysicsVector CenterOfMass diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 7589750c5b..c0b4b45934 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -797,7 +797,25 @@ namespace OpenSim.Region.Physics.OdePlugin #endregion - if (contacts[i].depth >= 0f && !checkDupe(contacts[i], p2.PhysicsActorType)) + // Logic for collision handling + // Note, that if *all* contacts are skipped (VolumeDetect) + // The prim still detects (and forwards) collision events but + // appears to be phantom for the world + Boolean skipThisContact = false; + + if (contacts[i].depth < 0f) + skipThisContact = true; + + if (checkDupe(contacts[i], p2.PhysicsActorType)) + skipThisContact = true; + + if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if ((p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if (!skipThisContact) { // If we're colliding against terrain if (name1 == "Terrain" || name2 == "Terrain") diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b15189e0b7..5ef94719b2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -5736,7 +5736,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (!m_host.ParentGroup.IsDeleted) { - m_host.ParentGroup.RootPart.SetVolumeDetect(detect); + m_host.ParentGroup.RootPart.ScriptSetVolumeDetect(detect!=0); } } }