diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index ae721757b0..c472176933 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -279,7 +279,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public string GetStats() { return string.Format( - "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", + "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7} {12,7}", + Util.EnvironmentTickCountSubtract(TickLastPacketReceived), PacketsReceived, PacketsSent, PacketsResent, diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index cd1e1c19d7..273e290d0f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -47,6 +47,7 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.CoreModules.World.Serialiser; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.XEngine; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; @@ -289,21 +290,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests { TestHelpers.InMethod(); - Scene scene = CreateTestScene(); + Scene scene = CreateScriptingEnabledTestScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); - ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); - TaskInventoryHelpers.AddScript(scene, so.RootPart); + TaskInventoryItem scriptItem + = TaskInventoryHelpers.AddScript( + scene, + so.RootPart, + "scriptItem", + "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. + // In the future, we need to be able to do this programatically more predicably. + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + m_chatEvent.WaitOne(60000); + // TODO: Need to have a test that checks the script is actually started but this involves a lot more // plumbing of the script engine and either pausing for events or more infrastructure to turn off various // script engine delays/asychronicity that isn't helpful in an automated regression testing context. SceneObjectGroup attSo = scene.GetSceneObjectGroup(so.Name); Assert.That(attSo.ContainsScripts(), Is.True); + + TaskInventoryItem reRezzedScriptItem = attSo.RootPart.Inventory.GetInventoryItem(scriptItem.Name); + IScriptModule xengine = scene.RequestModuleInterface(); + Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True); } [Test] @@ -379,29 +396,49 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); - TaskInventoryHelpers.AddScript(scene, so.RootPart); + TaskInventoryItem scriptTaskItem + = TaskInventoryHelpers.AddScript( + scene, + so.RootPart, + "scriptItem", + "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. // In the future, we need to be able to do this programatically more predicably. scene.EventManager.OnChatFromWorld += OnChatFromWorld; - SceneObjectGroup soRezzed - = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + SceneObjectGroup rezzedSo + = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); // Wait for chat to signal rezzed script has been started. m_chatEvent.WaitOne(60000); - scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, soRezzed); + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo); InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem); AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString()); + // TODO: It would probably be better here to check script state via the saving and retrieval of state + // information at a higher level, rather than having to inspect the serialization. XmlDocument soXml = new XmlDocument(); soXml.LoadXml(Encoding.UTF8.GetString(asset.Data)); XmlNodeList scriptStateNodes = soXml.GetElementsByTagName("ScriptState"); Assert.That(scriptStateNodes.Count, Is.EqualTo(1)); + + // Re-rez the attachment to check script running state + SceneObjectGroup reRezzedSo = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); + + // Wait for chat to signal rezzed script has been started. + m_chatEvent.WaitOne(60000); + + TaskInventoryItem reRezzedScriptItem = reRezzedSo.RootPart.Inventory.GetInventoryItem(scriptTaskItem.Name); + IScriptModule xengine = scene.RequestModuleInterface(); + Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True); + +// Console.WriteLine(soXml.OuterXml); } /// diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index a7ebeccdc9..ca9bd4ad07 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -81,18 +81,6 @@ namespace OpenSim.Region.CoreModules.UDP.Linden lock (m_scenes) m_scenes[scene.RegionInfo.RegionID] = scene; - scene.AddCommand( - "Comms", this, "image queues clear", - "image queues clear ", - "Clear the image queues (textures downloaded via UDP) for a particular client.", - (mod, cmd) => MainConsole.Instance.Output(HandleImageQueuesClear(cmd))); - - scene.AddCommand( - "Comms", this, "image queues show", - "image queues show ", - "Show the image queues (textures downloaded via UDP) for a particular client.", - (mod, cmd) => MainConsole.Instance.Output(GetImageQueuesReport(cmd))); - scene.AddCommand( "Comms", this, "show pqueues", "show pqueues [full]", @@ -105,8 +93,15 @@ namespace OpenSim.Region.CoreModules.UDP.Linden "Comms", this, "show queues", "show queues [full]", "Show queue data for each client", - "Without the 'full' option, only root agents are shown." - + " With the 'full' option child agents are also shown.", + "Without the 'full' option, only root agents are shown.\n" + + "With the 'full' option child agents are also shown.\n\n" + + "Type - Rt is a root (avatar) client whilst cd is a child (neighbour interacting) client.\n" + + "Since Last In - Time in milliseconds since last packet received.\n" + + "Pkts In - Number of packets processed from the client.\n" + + "Pkts Out - Number of packets sent to the client.\n" + + "Pkts Resent - Number of packets resent to the client.\n" + + "Bytes Unacked - Number of bytes transferred to the client that are awaiting acknowledgement.\n" + + "Q Pkts * - Number of packets of various types (land, wind, etc.) to be sent to the client that are waiting for available bandwidth.\n", (mod, cmd) => MainConsole.Instance.Output(GetQueuesReport(cmd))); scene.AddCommand( @@ -114,6 +109,12 @@ namespace OpenSim.Region.CoreModules.UDP.Linden "show image queues ", "Show the image queues (textures downloaded via UDP) for a particular client.", (mod, cmd) => MainConsole.Instance.Output(GetImageQueuesReport(cmd))); + + scene.AddCommand( + "Comms", this, "clear image queues", + "clear image queues ", + "Clear the image queues (textures downloaded via UDP) for a particular client.", + (mod, cmd) => MainConsole.Instance.Output(HandleImageQueuesClear(cmd))); scene.AddCommand( "Comms", this, "show throttles", @@ -373,17 +374,22 @@ namespace OpenSim.Region.CoreModules.UDP.Linden int maxNameLength = 18; int maxRegionNameLength = 14; int maxTypeLength = 4; - int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding; + + int totalInfoFieldsLength + = maxNameLength + columnPadding + + maxRegionNameLength + columnPadding + + maxTypeLength + columnPadding; report.Append(GetColumnEntry("User", maxNameLength, columnPadding)); report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding)); report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding)); report.AppendFormat( - "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}\n", + "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", + "Since", + "Pkts", "Pkts", "Pkts", - "Pkts", "Bytes", "Q Pkts", "Q Pkts", @@ -396,7 +402,8 @@ namespace OpenSim.Region.CoreModules.UDP.Linden report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", ""); report.AppendFormat( - "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}\n", + "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", + "Last In", "In", "Out", "Resent", @@ -417,22 +424,22 @@ namespace OpenSim.Region.CoreModules.UDP.Linden scene.ForEachClient( delegate(IClientAPI client) { + bool isChild = client.SceneAgent.IsChildAgent; + if (isChild && !showChildren) + return; + + string name = client.Name; + if (pname != "" && name != pname) + return; + + string regionName = scene.RegionInfo.RegionName; + + report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); + report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding)); + report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding)); + if (client is IStatsCollector) { - bool isChild = client.SceneAgent.IsChildAgent; - if (isChild && !showChildren) - return; - - string name = client.Name; - if (pname != "" && name != pname) - return; - - string regionName = scene.RegionInfo.RegionName; - - report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); - report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding)); - report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding)); - IStatsCollector stats = (IStatsCollector)client; report.AppendLine(stats.Report()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 71a430391e..a19d6d7f17 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -133,10 +133,7 @@ public sealed class BSPrim : PhysicsActor _parentPrim = null; // not a child or a parent _vehicle = new BSDynamics(this); // add vehicleness _childrenPrims = new List(); - if (_isPhysical) - _mass = CalculateMass(); - else - _mass = 0f; + _mass = CalculateMass(); // do the actual object creation at taint time _scene.TaintedObject(delegate() { @@ -149,22 +146,26 @@ public sealed class BSPrim : PhysicsActor { // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); // DetailLog("{0},Destroy", LocalID); + // Undo any vehicle properties _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); _scene.RemoveVehiclePrim(this); // just to make sure - // undo any dependance with/on other objects - if (_parentPrim != null) - { - // If I'm someone's child, tell them to forget about me. - _parentPrim.RemoveChildFromLinkset(this); - _parentPrim = null; - } - _scene.TaintedObject(delegate() { + // undo any dependance with/on other objects + if (_parentPrim != null) + { + // If I'm someone's child, tell them to forget about me. + _parentPrim.RemoveChildFromLinkset(this); + _parentPrim = null; + } + + // make sure there are no possible children depending on me + UnlinkAllChildren(); + // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. - BulletSimAPI.DestroyObject(_scene.WorldID, _localID); + BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); }); } @@ -177,8 +178,8 @@ public sealed class BSPrim : PhysicsActor _size = value; _scene.TaintedObject(delegate() { - if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass - BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical); + _mass = CalculateMass(); // changing size changes the mass + BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, Mass, IsPhysical); RecreateGeomAndObject(); }); } @@ -188,7 +189,7 @@ public sealed class BSPrim : PhysicsActor _pbs = value; _scene.TaintedObject(delegate() { - if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass + _mass = CalculateMass(); // changing the shape changes the mass RecreateGeomAndObject(); }); } @@ -272,7 +273,10 @@ public sealed class BSPrim : PhysicsActor DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID); _childrenPrims.Add(child); child._parentPrim = this; // the child has gained a parent - RecreateGeomAndObject(); // rebuild my shape with the new child added + // RecreateGeomAndObject(); // rebuild my shape with the new child added + LinkAChildToMe(pchild); // build the physical binding between me and the child + + _mass = CalculateMass(); } }); return; @@ -288,14 +292,21 @@ public sealed class BSPrim : PhysicsActor if (_childrenPrims.Contains(child)) { DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); - DetailLog("{0},RemoveChildToLinkset,child={1}", LocalID, pchild.LocalID); - if (!BulletSimAPI.RemoveConstraintByID(_scene.WorldID, child.LocalID)) - { - m_log.ErrorFormat("{0}: RemoveChildFromLinkset: Failed remove constraint for {1}", LogHeader, child.LocalID); - } + DetailLog("{0},RemoveChildFromLinkset,child={1}", LocalID, pchild.LocalID); _childrenPrims.Remove(child); child._parentPrim = null; // the child has lost its parent - RecreateGeomAndObject(); // rebuild my shape with the child removed + if (_childrenPrims.Count == 0) + { + // if the linkset is empty, make sure all linkages have been removed + UnlinkAllChildren(); + } + else + { + // RecreateGeomAndObject(); // rebuild my shape with the child removed + UnlinkAChildFromMe(pchild); + } + + _mass = CalculateMass(); } else { @@ -314,12 +325,19 @@ public sealed class BSPrim : PhysicsActor // Set motion values to zero. // Do it to the properties so the values get set in the physics engine. // Push the setting of the values to the viewer. + // Called at taint time! private void ZeroMotion() { - Velocity = OMV.Vector3.Zero; + _velocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; - RotationalVelocity = OMV.Vector3.Zero; - base.RequestPhysicsterseUpdate(); + _rotationalVelocity = OMV.Vector3.Zero; + + // Zero some other properties directly into the physics engine + IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID); + BulletSimAPI.SetVelocity2(obj, OMV.Vector3.Zero); + BulletSimAPI.SetAngularVelocity2(obj, OMV.Vector3.Zero); + BulletSimAPI.SetInterpolation2(obj, OMV.Vector3.Zero, OMV.Vector3.Zero); + BulletSimAPI.ClearForces2(obj); } public override void LockAngularMotion(OMV.Vector3 axis) @@ -347,9 +365,17 @@ public sealed class BSPrim : PhysicsActor }); } } + + // Return the effective mass of the object. Non-physical objects do not have mass. public override float Mass { - get { return _mass; } + get { + if (IsPhysical) + return _mass; + else + return 0f; + } } + public override OMV.Vector3 Force { get { return _force; } set { @@ -429,7 +455,8 @@ public sealed class BSPrim : PhysicsActor // Called from Scene when doing simulation step so we're in taint processing time. public void StepVehicle(float timeStep) { - _vehicle.Step(timeStep); + if (IsPhysical) + _vehicle.Step(timeStep); } // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more @@ -526,20 +553,13 @@ public sealed class BSPrim : PhysicsActor { // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); // non-physical things work best with a mass of zero - if (IsStatic) - { - _mass = 0f; - } - else + if (!IsStatic) { _mass = CalculateMass(); - // If it's dynamic, make sure the hull has been created for it - // This shouldn't do much work if the object had previously been built RecreateGeomAndObject(); - } - DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, _mass); - BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); + DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, Mass); + BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), Mass); } // prims don't fly @@ -1234,7 +1254,7 @@ public sealed class BSPrim : PhysicsActor if (IsRootOfLinkset) { // Create a linkset around this object - CreateLinksetWithConstraints(); + CreateLinkset(); } else { @@ -1247,30 +1267,6 @@ public sealed class BSPrim : PhysicsActor } } - // Create a linkset by creating a compound hull at the root prim that consists of all - // the children. - // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution - void CreateLinksetWithCompoundHull() - { - // If I am the root prim of a linkset, replace my physical shape with all the - // pieces of the children. - // All of the children should have called CreateGeom so they have a hull - // in the physics engine already. Here we pull together all of those hulls - // into one shape. - int totalPrimsInLinkset = _childrenPrims.Count + 1; - // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset); - ShapeData[] shapes = new ShapeData[totalPrimsInLinkset]; - FillShapeInfo(out shapes[0]); - int ii = 1; - foreach (BSPrim prim in _childrenPrims) - { - // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID); - prim.FillShapeInfo(out shapes[ii]); - ii++; - } - BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes); - } - // Copy prim's info into the BulletSim shape description structure public void FillShapeInfo(out ShapeData shape) { @@ -1280,7 +1276,7 @@ public sealed class BSPrim : PhysicsActor shape.Rotation = _orientation; shape.Velocity = _velocity; shape.Scale = _scale; - shape.Mass = _isPhysical ? _mass : 0f; + shape.Mass = Mass; shape.Buoyancy = _buoyancy; shape.HullKey = _hullKey; shape.MeshKey = _meshKey; @@ -1290,45 +1286,73 @@ public sealed class BSPrim : PhysicsActor shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; } + #region Linkset creation and destruction + // Create the linkset by putting constraints between the objects of the set so they cannot move // relative to each other. - // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added - void CreateLinksetWithConstraints() + void CreateLinkset() { DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); // remove any constraints that might be in place - foreach (BSPrim prim in _childrenPrims) - { - DebugLog("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); - BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); - } + DebugLog("{0}: CreateLinkset: RemoveConstraints between me and any children", LogHeader, LocalID); + BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); + // create constraints between the root prim and each of the children foreach (BSPrim prim in _childrenPrims) { - // Zero motion for children so they don't interpolate - prim.ZeroMotion(); - - // relative position normalized to the root prim - OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation); - OMV.Vector3 childRelativePosition = (prim._position - this._position) * invThisOrientation; - - // relative rotation of the child to the parent - OMV.Quaternion childRelativeRotation = invThisOrientation * prim._orientation; - - // this is a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 - DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); - BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, - childRelativePosition, - childRelativeRotation, - OMV.Vector3.Zero, - OMV.Quaternion.Identity, - OMV.Vector3.Zero, OMV.Vector3.Zero, - OMV.Vector3.Zero, OMV.Vector3.Zero); + LinkAChildToMe(prim); } } + // Create a constraint between me (root of linkset) and the passed prim (the child). + // Called at taint time! + private void LinkAChildToMe(BSPrim childPrim) + { + // Zero motion for children so they don't interpolate + childPrim.ZeroMotion(); + + // relative position normalized to the root prim + OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation); + OMV.Vector3 childRelativePosition = (childPrim._position - this._position) * invThisOrientation; + + // relative rotation of the child to the parent + OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim._orientation; + + // create a constraint that allows no freedom of movement between the two objects + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 + DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); + DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID); + BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, childPrim.LocalID, + childRelativePosition, + childRelativeRotation, + OMV.Vector3.Zero, + OMV.Quaternion.Identity, + OMV.Vector3.Zero, OMV.Vector3.Zero, + OMV.Vector3.Zero, OMV.Vector3.Zero); + } + + // Remove linkage between myself and a particular child + // Called at taint time! + private void UnlinkAChildFromMe(BSPrim childPrim) + { + DebugLog("{0}: UnlinkAChildFromMe: RemoveConstraint between root prim {1} and child prim {2}", + LogHeader, LocalID, childPrim.LocalID); + DetailLog("{0},UnlinkAChildFromMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID); + BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID); + } + + // Remove linkage between myself and any possible children I might have + // Called at taint time! + private void UnlinkAllChildren() + { + DebugLog("{0}: UnlinkAllChildren:", LogHeader); + DetailLog("{0},UnlinkAllChildren,taint", LocalID); + BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); + } + + #endregion // Linkset creation and destruction + // Rebuild the geometry and object. // This is called when the shape changes so we need to recreate the mesh/hull. // No locking here because this is done when the physics engine is not simulating @@ -1405,7 +1429,7 @@ public sealed class BSPrim : PhysicsActor // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. // Updates only for individual prims and for the root object of a linkset. - if (this._parentPrim == null) + if (_parentPrim == null) { // Assign to the local variables so the normal set action does not happen _position = entprop.Position; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 87734853df..7cc3fe3ca5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -630,6 +630,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters public override void Dispose() { // m_log.DebugFormat("{0}: Dispose()", LogHeader); + + // make sure no stepping happens while we're deleting stuff + m_initialized = false; + + foreach (KeyValuePair kvp in m_avatars) + { + kvp.Value.Destroy(); + } + m_avatars.Clear(); + + foreach (KeyValuePair kvp in m_prims) + { + kvp.Value.Destroy(); + } + m_prims.Clear(); + + // Anything left in the unmanaged code should be cleaned out + BulletSimAPI.Shutdown(WorldID); + + // Not logging any more + PhysicsLogging.Close(); } public override Dictionary GetTopColliders() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index babb707b75..54a8cfde27 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -291,13 +291,14 @@ public static extern void SetDebugLogCallback(DebugLogCallback callback); // =============================================================================== // =============================================================================== // =============================================================================== -// A new version of the API that moves all the logic out of the C++ code and into +// A new version of the API that enables moving all the logic out of the C++ code and into // the C# code. This will make modifications easier for the next person. // This interface passes the actual pointers to the objects in the unmanaged // address space. All the management (calls for creation/destruction/lookup) // is done in the C# code. -// The names have a 2 tacked on. This will be removed as the code gets rebuilt -// and the old code is removed from the C# code. +// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt +// and the old code is removed. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr GetSimHandle2(uint worldID); @@ -307,8 +308,101 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id); +// =============================================================================== [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr ClearForces2(IntPtr obj); +public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, + int maxCollisions, IntPtr collisionArray, + int maxUpdates, IntPtr updateArray); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool UpdateParameter2(IntPtr sim, uint localID, String parm, float value); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetHeightmap2(IntPtr sim, float[] heightmap); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void Shutdown2(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int PhysicsStep2(IntPtr sim, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, + out IntPtr updatedEntitiesPtr, + out int collidersCount, + out IntPtr collidersPtr); + +/* +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateMesh2(IntPtr sim, int indicesCount, int* indices, int verticesCount, float* vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool BuildHull2(IntPtr sim, IntPtr mesh); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ReleaseHull2(IntPtr sim, IntPtr mesh); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DestroyMesh2(IntPtr sim, IntPtr mesh); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData); +*/ + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetPosition2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Quaternion GetOrientation2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetDeactivationTime2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetFriction2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetRestitution2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags); @@ -319,5 +413,35 @@ public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags); +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool UpdateInertiaTensor2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetGravity2(IntPtr obj, Vector3 val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr ClearForces2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetMargin2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DestroyObject2(IntPtr world, uint id); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpPhysicsStatistics2(IntPtr sim); + } } diff --git a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs index fba03abcf0..0a2b30a279 100644 --- a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs @@ -79,9 +79,27 @@ namespace OpenSim.Tests.Common /// /// The item that was added public static TaskInventoryItem AddScript(Scene scene, SceneObjectPart part) + { + return AddScript(scene, part, "scriptItem", "default { state_entry() { llSay(0, \"Hello World\"); } }"); + } + + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// Name of the script to add + /// LSL script source + /// The item that was added + public static TaskInventoryItem AddScript( + Scene scene, SceneObjectPart part, string scriptName, string scriptSource) { AssetScriptText ast = new AssetScriptText(); - ast.Source = "default { state_entry() { llSay(0, \"Hello World\"); } }"; + ast.Source = scriptSource; ast.Encode(); UUID assetUuid = new UUID("00000000-0000-0000-1000-000000000000"); @@ -91,7 +109,7 @@ namespace OpenSim.Tests.Common scene.AssetService.Store(asset); TaskInventoryItem item = new TaskInventoryItem - { Name = "scriptItem", AssetID = assetUuid, ItemID = itemUuid, + { Name = scriptName, AssetID = assetUuid, ItemID = itemUuid, Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; part.Inventory.AddInventoryItem(item, true); diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 8791ba57de..322322a701 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index da98509500..493c8cbc84 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 9af5dab4c2..2bd13b8644 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 3d4b630756..af3a078bfe 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ