From 7a574be3fd28ffbd9bce4cfa08451d705728fa20 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 00:12:07 +0100 Subject: [PATCH 1/9] Remove redundant prim_geom != IntPtr.Zero checks in ODEPrim. prim_geom == IntPtr.Zero only before a new add prim taint is processed (which is the first taint) or in operations such as scale change which are done in taint or under lock. Therefore, we can remove these checks which were not consistently applied anyway. If there is a genuine problem, better to see it quickly in a NullReferenceException than hide the bug. --- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 224 +++++++++----------- 1 file changed, 98 insertions(+), 126 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 7d67da3c8e..0a8cf75bcd 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -156,7 +156,15 @@ namespace OpenSim.Region.Physics.OdePlugin /// public IntPtr m_targetSpace = IntPtr.Zero; + /// + /// The prim geometry, used for collision detection. + /// + /// + /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or + /// mesh change) or when the physical prim is being removed from the scene. + /// public IntPtr prim_geom { get; private set; } + public IntPtr _triMeshData { get; private set; } private IntPtr _linkJointGroup = IntPtr.Zero; @@ -325,14 +333,11 @@ namespace OpenSim.Region.Physics.OdePlugin { prim_geom = geom; //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - _parent_scene.geom_name_map[prim_geom] = Name; - _parent_scene.actor_name_map[prim_geom] = this; - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + + _parent_scene.geom_name_map[prim_geom] = Name; if (childPrim) { @@ -765,11 +770,8 @@ namespace OpenSim.Region.Physics.OdePlugin m_collisionCategories &= ~CollisionCategories.Body; m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); d.BodyDestroy(Body); lock (childrenPrim) @@ -793,11 +795,8 @@ namespace OpenSim.Region.Physics.OdePlugin m_collisionCategories &= ~CollisionCategories.Body; m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); Body = IntPtr.Zero; } @@ -864,10 +863,7 @@ namespace OpenSim.Region.Physics.OdePlugin // _parent_scene.waitForSpaceUnlock(m_targetSpace); try { - if (prim_geom == IntPtr.Zero) - { - SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); - } + SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); } catch (AccessViolationException) { @@ -890,73 +886,67 @@ namespace OpenSim.Region.Physics.OdePlugin #if SPAM Console.WriteLine("ZProcessTaints for " + Name); #endif + + // This must be processed as the very first taint so that later operations have a prim_geom to work with + // if this is a new prim. if (m_taintadd) - { changeadd(); - } - - if (prim_geom != IntPtr.Zero) - { - if (!_position.ApproxEquals(m_taintposition, 0f)) - changemove(); - if (m_taintrot != _orientation) - { - if (childPrim && IsPhysical) // For physical child prim... - { - rotate(); - // KF: ODE will also rotate the parent prim! - // so rotate the root back to where it was - OdePrim parent = (OdePrim)_parent; - parent.rotate(); - } - else - { - //Just rotate the prim - rotate(); - } + if (!_position.ApproxEquals(m_taintposition, 0f)) + changemove(); + + if (m_taintrot != _orientation) + { + if (childPrim && IsPhysical) // For physical child prim... + { + rotate(); + // KF: ODE will also rotate the parent prim! + // so rotate the root back to where it was + OdePrim parent = (OdePrim)_parent; + parent.rotate(); + } + else + { + //Just rotate the prim + rotate(); } - - if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) - changePhysicsStatus(); - - if (!_size.ApproxEquals(m_taintsize, 0f)) - changesize(); - - if (m_taintshape) - changeshape(); - - if (m_taintforce) - changeAddForce(); - - if (m_taintaddangularforce) - changeAddAngularForce(); - - if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) - changeSetTorque(); - - if (m_taintdisable) - changedisable(); - - if (m_taintselected != m_isSelected) - changeSelectedStatus(); - - if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) - changevelocity(); - - if (m_taintparent != _parent) - changelink(); - - if (m_taintCollidesWater != m_collidesWater) - changefloatonwater(); - - if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) - changeAngularLock(); - } - else - { - m_log.ErrorFormat("[PHYSICS]: The scene reused a disposed PhysActor for {0}! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)", Name); } + + if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) + changePhysicsStatus(); + + if (!_size.ApproxEquals(m_taintsize, 0f)) + changesize(); + + if (m_taintshape) + changeshape(); + + if (m_taintforce) + changeAddForce(); + + if (m_taintaddangularforce) + changeAddAngularForce(); + + if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) + changeSetTorque(); + + if (m_taintdisable) + changedisable(); + + if (m_taintselected != m_isSelected) + changeSelectedStatus(); + + if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) + changevelocity(); + + if (m_taintparent != _parent) + changelink(); + + if (m_taintCollidesWater != m_collidesWater) + changefloatonwater(); + + if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) + changeAngularLock(); } /// @@ -1093,18 +1083,10 @@ Console.WriteLine("ZProcessTaints for " + Name); prm.m_collisionCategories |= CollisionCategories.Body; prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - if (prm.prim_geom == IntPtr.Zero) - { - m_log.WarnFormat( - "[PHYSICS]: Unable to link one of the linkset elements {0} for parent {1}. No geom yet", - prm.Name, prim.Name); - continue; - } //Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); - d.Quaternion quat = new d.Quaternion(); quat.W = prm._orientation.W; quat.X = prm._orientation.X; @@ -1303,11 +1285,8 @@ Console.WriteLine("ZProcessTaints for " + Name); disableBodySoft(); } - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); if (IsPhysical) { @@ -1328,11 +1307,8 @@ Console.WriteLine("ZProcessTaints for " + Name); if (m_collidesWater) m_collisionFlags |= CollisionCategories.Water; - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); if (IsPhysical) { @@ -1472,6 +1448,9 @@ Console.WriteLine("CreateGeom:"); } else { + m_log.WarnFormat( + "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID); + return false; } } @@ -1505,16 +1484,13 @@ Console.WriteLine("changeadd 1"); #endif CreateGeom(m_targetSpace, mesh); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.GeomSetQuaternion(prim_geom, ref myrot); - } + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.GeomSetQuaternion(prim_geom, ref myrot); if (IsPhysical && Body == IntPtr.Zero) enableBody(); @@ -1588,13 +1564,11 @@ Console.WriteLine(" JointCreateFixed"); m_targetSpace = tempspace; // _parent_scene.waitForSpaceUnlock(m_targetSpace); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); // _parent_scene.waitForSpaceUnlock(m_targetSpace); - d.SpaceAdd(m_targetSpace, prim_geom); - } + d.SpaceAdd(m_targetSpace, prim_geom); changeSelectedStatus(); @@ -2045,18 +2019,16 @@ Console.WriteLine(" JointCreateFixed"); { m_collidesWater = m_taintCollidesWater; - if (prim_geom != IntPtr.Zero) + if (m_collidesWater) { - if (m_collidesWater) - { - m_collisionFlags |= CollisionCategories.Water; - } - else - { - m_collisionFlags &= ~CollisionCategories.Water; - } - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + m_collisionFlags |= CollisionCategories.Water; } + else + { + m_collisionFlags &= ~CollisionCategories.Water; + } + + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); } /// From 06552f217ebd9301fd487c788a13fd75d61a46de Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 00:54:48 +0100 Subject: [PATCH 2/9] Add TestSetPhysics() to SOP status tests --- .../Framework/Scenes/SceneObjectPart.cs | 9 ++++++--- .../Scenes/Tests/SceneObjectStatusTests.cs | 20 +++++++++++++++++++ OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 046553ba6a..d2cd37dc8d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1706,6 +1706,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) { + if (ParentGroup.Scene == null) + return; + if (!ParentGroup.Scene.PhysicalPrims && UsePhysics) return; @@ -4161,7 +4164,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { string hingeString = "hingejoint"; return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString); @@ -4177,7 +4180,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { string ballString = "balljoint"; return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString); @@ -4193,7 +4196,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { return IsHingeJoint() || IsBallJoint(); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 2a342d50c8..16e8b63378 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -62,5 +62,25 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } + + [Test] + public void TestSetPhysics() + { + TestHelpers.InMethod(); + +// Scene scene = SceneSetupHelpers.SetupScene(); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, UUID.Zero); + SceneObjectPart rootPart = so.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + so.ScriptSetPhysicsStatus(true); + +// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + + so.ScriptSetPhysicsStatus(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 318758d984..7a6b1cf8d5 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -153,7 +153,7 @@ namespace OpenSim.Tests.Common PhysicsPluginManager physicsPluginManager = new PhysicsPluginManager(); physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); testScene.PhysicsScene - = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); + = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); testScene.RegionInfo.EstateSettings = new EstateSettings(); testScene.LoginsDisabled = false; From 71900968b221b89860d1cef162f3b0d1236e1c73 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 01:01:24 +0100 Subject: [PATCH 3/9] refactor: extract common setup code in SceneObjectStatusTests --- .../Scenes/Tests/SceneObjectStatusTests.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 16e8b63378..b8e1b92c21 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -43,22 +43,30 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class SceneObjectStatusTests { + private TestScene m_scene; + private SceneObjectGroup m_so1; + + [SetUp] + public void Init() + { + m_scene = SceneHelpers.SetupScene(); + SceneObjectGroup m_so1 = SceneHelpers.CreateSceneObject(1, UUID.Zero); + } + [Test] public void TestSetPhantom() { TestHelpers.InMethod(); -// Scene scene = SceneSetupHelpers.SetupScene(); - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, UUID.Zero); - SceneObjectPart rootPart = so.RootPart; + SceneObjectPart rootPart = m_so1.RootPart; Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); - so.ScriptSetPhantomStatus(true); + m_so1.ScriptSetPhantomStatus(true); // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); - so.ScriptSetPhantomStatus(false); + m_so1.ScriptSetPhantomStatus(false); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } @@ -68,17 +76,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); -// Scene scene = SceneSetupHelpers.SetupScene(); - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, UUID.Zero); - SceneObjectPart rootPart = so.RootPart; + SceneObjectPart rootPart = m_so1.RootPart; Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); - so.ScriptSetPhysicsStatus(true); + m_so1.ScriptSetPhysicsStatus(true); // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); - so.ScriptSetPhysicsStatus(false); + m_so1.ScriptSetPhysicsStatus(false); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } From 17bf2a62db39ba58ca691a6754bf79fe6b3ee474 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 01:09:19 +0100 Subject: [PATCH 4/9] Add test for correct physics status on linking two physics objects Also fixes last build break. --- .../Scenes/Tests/SceneObjectStatusTests.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index b8e1b92c21..6270ac148d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using NUnit.Framework; using OpenMetaverse; @@ -44,13 +45,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests public class SceneObjectStatusTests { private TestScene m_scene; + private UUID m_ownerId = TestHelpers.ParseTail(0x1); private SceneObjectGroup m_so1; + private SceneObjectGroup m_so2; [SetUp] public void Init() { m_scene = SceneHelpers.SetupScene(); - SceneObjectGroup m_so1 = SceneHelpers.CreateSceneObject(1, UUID.Zero); + m_so1 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so1", 0x10); + m_so2 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so2", 0x20); } [Test] @@ -86,7 +90,27 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_so1.ScriptSetPhysicsStatus(false); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsBothPhysical() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); } } } \ No newline at end of file From 9ac48b2aff2ddd00821b7e6ecd71ce134f7a0f25 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 01:43:09 +0100 Subject: [PATCH 5/9] Fix a bug where linking a non-physical prim with a physical prim as root would make the non-physical prim phantom rather than part of the physics object. On region restart, the whole object would become physical as expected. Observed behaviour from elsewhere is that all prims in a new linkset should take on the status of the root prim. Add regression test for this behaviour. --- .../Framework/Scenes/SceneObjectGroup.cs | 3 +++ .../Scenes/Tests/SceneObjectStatusTests.cs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 8e786c150e..49a3485183 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2010,6 +2010,7 @@ namespace OpenSim.Region.Framework.Scenes linkPart.CreateSelected = true; linkPart.LinkNum = linkNum++; + linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); SceneObjectPart[] ogParts = objectGroup.Parts; Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) @@ -2220,6 +2221,8 @@ namespace OpenSim.Region.Framework.Scenes oldRot = part.RotationOffset; Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; part.RotationOffset = newRot; + + part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); } /// diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 6270ac148d..91f4a3433d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -112,5 +112,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsRootPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } } } \ No newline at end of file From d5c724e5b8cc15ce278b80070238e72a2e4ea0e8 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 01:51:57 +0100 Subject: [PATCH 6/9] Add regression test for prim status when root prim in a new linkset is non-physical --- .../Framework/Scenes/SceneObjectPart.cs | 2 +- .../Scenes/Tests/SceneObjectStatusTests.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d2cd37dc8d..1592131dc2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1708,7 +1708,7 @@ namespace OpenSim.Region.Framework.Scenes { if (ParentGroup.Scene == null) return; - + if (!ParentGroup.Scene.PhysicalPrims && UsePhysics) return; diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 91f4a3433d..8cdd64507e 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -131,5 +131,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsChildPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + } } } \ No newline at end of file From 77a7de87e1c89385bc906d1b409ec1c94c41b9e6 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 02:45:16 +0100 Subject: [PATCH 7/9] Add test for setting physics in a linkset --- .../Scenes/Tests/SceneObjectStatusTests.cs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 8cdd64507e..882031c782 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests } [Test] - public void TestSetPhantom() + public void TestSetPhantomSinglePrim() { TestHelpers.InMethod(); @@ -76,7 +76,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests } [Test] - public void TestSetPhysics() + public void TestSetPhysicsSinglePrim() { TestHelpers.InMethod(); @@ -92,6 +92,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } + + [Test] + public void TestSetPhysicsLinkset() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + + m_so1.ScriptSetPhysicsStatus(false); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } /// /// Test that linking results in the correct physical status for all linkees. From f60959459574b1473dbe35d780aa0fbe4d688580 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 03:23:51 +0100 Subject: [PATCH 8/9] refactor: Simplify ODEPrim.AddChildPrim() by returning early where appropriate. --- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 224 ++++++++++---------- 1 file changed, 113 insertions(+), 111 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 0a8cf75bcd..cbb49ace54 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -1042,142 +1042,144 @@ Console.WriteLine("ZProcessTaints for " + Name); /// Child prim private void AddChildPrim(OdePrim prim) { -//Console.WriteLine("AddChildPrim " + Name); - if (LocalID != prim.LocalID) + if (LocalID == prim.LocalID) + return; + + if (Body == IntPtr.Zero) { - if (Body == IntPtr.Zero) - { - Body = d.BodyCreate(_parent_scene.world); - setMass(); - } - if (Body != IntPtr.Zero) - { - lock (childrenPrim) - { - if (!childrenPrim.Contains(prim)) - { + Body = d.BodyCreate(_parent_scene.world); + setMass(); + } + + lock (childrenPrim) + { + if (childrenPrim.Contains(prim)) + return; + //Console.WriteLine("childrenPrim.Add " + prim); - childrenPrim.Add(prim); - - foreach (OdePrim prm in childrenPrim) - { - d.Mass m2; - d.MassSetZero(out m2); - d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); + childrenPrim.Add(prim); - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; + foreach (OdePrim prm in childrenPrim) + { + d.Mass m2; + d.MassSetZero(out m2); + d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - d.MassRotate(ref m2, ref mat); - d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); - d.MassAdd(ref pMass, ref m2); - } - - foreach (OdePrim prm in childrenPrim) - { - prm.m_collisionCategories |= CollisionCategories.Body; - prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; + + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + d.MassRotate(ref m2, ref mat); + d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); + d.MassAdd(ref pMass, ref m2); + } + + foreach (OdePrim prm in childrenPrim) + { + prm.m_collisionCategories |= CollisionCategories.Body; + prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); //Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); - d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); - d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); + d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); + d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - if (Body != IntPtr.Zero) - { - d.GeomSetBody(prm.prim_geom, Body); - prm.childPrim = true; - d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); - //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); - } - else - { - m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); - } + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + if (Body != IntPtr.Zero) + { + d.GeomSetBody(prm.prim_geom, Body); + prm.childPrim = true; + d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); + //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); + } + else + { + m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); + } - prm.m_interpenetrationcount = 0; - prm.m_collisionscore = 0; - prm.m_disabled = false; + prm.m_interpenetrationcount = 0; + prm.m_collisionscore = 0; + prm.m_disabled = false; - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - prm.createAMotor(m_angularlock); - } - prm.Body = Body; - _parent_scene.ActivatePrim(prm); - } + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) + { + prm.createAMotor(m_angularlock); + } + prm.Body = Body; + _parent_scene.ActivatePrim(prm); + } - m_collisionCategories |= CollisionCategories.Body; - m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + m_collisionCategories |= CollisionCategories.Body; + m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); //Console.WriteLine(" Post GeomSetCategoryBits 2"); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - d.Quaternion quat2 = new d.Quaternion(); - quat2.W = _orientation.W; - quat2.X = _orientation.X; - quat2.Y = _orientation.Y; - quat2.Z = _orientation.Z; + d.Quaternion quat2 = new d.Quaternion(); + quat2.W = _orientation.W; + quat2.X = _orientation.X; + quat2.Y = _orientation.Y; + quat2.Z = _orientation.Z; - d.Matrix3 mat2 = new d.Matrix3(); - d.RfromQ(out mat2, ref quat2); - d.GeomSetBody(prim_geom, Body); - d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - //d.GeomSetOffsetRotation(prim_geom, ref mat2); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); + d.Matrix3 mat2 = new d.Matrix3(); + d.RfromQ(out mat2, ref quat2); + d.GeomSetBody(prim_geom, Body); + d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + //d.GeomSetOffsetRotation(prim_geom, ref mat2); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); - d.BodySetAutoDisableFlag(Body, true); - d.BodySetAutoDisableSteps(Body, body_autodisable_frames); + d.BodySetAutoDisableFlag(Body, true); + d.BodySetAutoDisableSteps(Body, body_autodisable_frames); - m_interpenetrationcount = 0; - m_collisionscore = 0; - m_disabled = false; + m_interpenetrationcount = 0; + m_collisionscore = 0; + m_disabled = false; - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - createAMotor(m_angularlock); - } - d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); - if (m_vehicle.Type != Vehicle.TYPE_NONE) - m_vehicle.Enable(Body, _parent_scene); - - _parent_scene.ActivatePrim(this); - } - } + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) + { + createAMotor(m_angularlock); } + + d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); + + if (m_vehicle.Type != Vehicle.TYPE_NONE) + m_vehicle.Enable(Body, _parent_scene); + + _parent_scene.ActivatePrim(this); } } private void ChildSetGeom(OdePrim odePrim) { +// m_log.DebugFormat( +// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + //if (IsPhysical && Body != IntPtr.Zero) lock (childrenPrim) { From ae2b8f70074e4dfe2cbbd03dd543c7468fc50cc1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 21 Apr 2012 03:42:54 +0100 Subject: [PATCH 9/9] Comment out spurious Body != IntPtr.Zero code after disableBody(), since disableBody() sets Body == IntPtr.Zero on all code paths. --- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 27 +++++++++++++------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 3 ++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index cbb49ace54..3f88353453 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -1056,7 +1056,9 @@ Console.WriteLine("ZProcessTaints for " + Name); if (childrenPrim.Contains(prim)) return; -//Console.WriteLine("childrenPrim.Add " + prim); +// m_log.DebugFormat( +// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID); + childrenPrim.Add(prim); foreach (OdePrim prm in childrenPrim) @@ -1194,12 +1196,14 @@ Console.WriteLine("ZProcessTaints for " + Name); //prm.childPrim = false; } } + disableBody(); - if (Body != IntPtr.Zero) - { - _parent_scene.DeactivatePrim(this); - } + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } lock (childrenPrim) { @@ -1213,6 +1217,9 @@ Console.WriteLine("ZProcessTaints for " + Name); private void ChildDelink(OdePrim odePrim) { +// m_log.DebugFormat( +// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + // Okay, we have a delinked child.. need to rebuild the body. lock (childrenPrim) { @@ -1227,6 +1234,7 @@ Console.WriteLine("ZProcessTaints for " + Name); //prm.childPrim = false; } } + disableBody(); lock (childrenPrim) @@ -1235,10 +1243,11 @@ Console.WriteLine("ZProcessTaints for " + Name); childrenPrim.Remove(odePrim); } - if (Body != IntPtr.Zero) - { - _parent_scene.DeactivatePrim(this); - } + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } lock (childrenPrim) { diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 842ff916dc..409b27be02 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -2226,7 +2226,8 @@ namespace OpenSim.Region.Physics.OdePlugin /// internal void RemovePrimThreadLocked(OdePrim prim) { -//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); +// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); + lock (prim) { RemoveCollisionEventReporting(prim);