Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
	OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
avinationmerge
Melanie 2012-12-16 21:19:30 +00:00
commit 0a876a305c
43 changed files with 1161 additions and 534 deletions

View File

@ -97,7 +97,7 @@ namespace OpenSim.Framework.Console
if (!UUID.TryParse(rawUuid, out uuid))
{
if (console != null)
console.OutputFormat("{0} is not a valid uuid", rawUuid);
console.OutputFormat("ERROR: {0} is not a valid uuid", rawUuid);
return false;
}
@ -110,7 +110,7 @@ namespace OpenSim.Framework.Console
if (!uint.TryParse(rawLocalId, out localId))
{
if (console != null)
console.OutputFormat("{0} is not a valid local id", localId);
console.OutputFormat("ERROR: {0} is not a valid local id", localId);
return false;
}
@ -118,7 +118,7 @@ namespace OpenSim.Framework.Console
if (localId == 0)
{
if (console != null)
console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId);
console.OutputFormat("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
return false;
}
@ -150,10 +150,30 @@ namespace OpenSim.Framework.Console
}
if (console != null)
console.OutputFormat("{0} is not a valid UUID or local id", rawId);
console.OutputFormat("ERROR: {0} is not a valid UUID or local id", rawId);
return false;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='console'>Can be null if no console is available.</param>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
{
if (!int.TryParse(rawConsoleInt, out i))
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid integer", rawConsoleInt);
return false;
}
return true;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3

View File

@ -92,6 +92,7 @@ namespace OpenSim.Framework
// Attempt to install the plugin disabled
if (Install(ps, pack) == true)
{
MainConsole.Instance.Output("Ignore the following error...");
PluginRegistry.Update(ps);
Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id);
PluginRegistry.DisableAddin(addin.Id);
@ -479,6 +480,7 @@ namespace OpenSim.Framework
ConsoleProgressStatus ps = new ConsoleProgressStatus(false);
if (!AddinManager.AddinEngine.IsAddinLoaded(addin.Id))
{
MainConsole.Instance.Output("Ignore the following error...");
AddinManager.Registry.Rebuild(ps);
AddinManager.AddinEngine.LoadAddin(ps, addin.Id);
}

View File

@ -12077,11 +12077,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (logPacket)
m_log.DebugFormat(
"[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
}
if (!ProcessPacketMethod(packet))
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
m_log.WarnFormat(
"[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
}
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)

View File

@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
#region Internal functions
public AssetMetadata FetchMetadata(string url, UUID assetID)
private AssetMetadata FetchMetadata(string url, UUID assetID)
{
if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/";
@ -86,6 +86,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
return meta;
}
private AssetBase FetchAsset(string url, UUID assetID)
{
// Test if it's already here
AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
if (asset == null)
{
if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/";
asset = m_scene.AssetService.Get(url + assetID.ToString());
//if (asset != null)
// m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url);
//else
// m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url);
}
return asset;
}
public bool PostAsset(string url, AssetBase asset)
{
if (asset != null)
@ -228,11 +249,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
if (meta == null)
return;
// The act of gathering UUIDs downloads the assets from the remote server
// The act of gathering UUIDs downloads some assets from the remote server
// but not all...
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count);
bool success = true;
foreach (UUID uuid in ids.Keys)
if (FetchAsset(userAssetURL, uuid) == null)
success = false;
// maybe all pieces got here...
if (!success)
m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL);
else
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
}

View File

@ -181,6 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
// searhc the user accounts service
List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
List<UserData> users = new List<UserData>();
@ -196,6 +197,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
}
}
// search the local cache
foreach (UserData data in m_UserCache.Values)
if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
(data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
users.Add(data);
AddAdditionalUsers(avatarID, query, users);
AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
@ -433,6 +440,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
public void AddUser(UUID uuid, string first, string last, string homeURL)
{
//m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
if (homeURL == string.Empty)
return;
AddUser(uuid, homeURL + ";" + first + " " + last);
}

View File

@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
public void RemoveRegion(Scene scene)
{
m_scene.EventManager.OnClientLogin -= OnNewClient;
m_scene.EventManager.OnNewClient -= OnNewClient;
}
public void RegionLoaded(Scene scene)
@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
return;
m_scene = scene;
m_scene.EventManager.OnClientLogin += OnNewClient;
m_scene.EventManager.OnNewClient += OnNewClient;
m_scene.RegisterModuleInterface<ISoundModule>(this);
}

View File

@ -26,9 +26,10 @@
*/
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
@ -113,6 +114,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation
if (m_scenePresence.IsChildAgent)
return;
// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Removing animation {0} for {1}", animID, m_scenePresence.Name);
if (m_animations.Remove(animID))
SendAnimPack();
}
@ -519,6 +522,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
if (m_scenePresence.IsChildAgent)
return;
// m_log.DebugFormat(
// "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'",
// string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())),
// string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())),
// string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString())));
m_scenePresence.Scene.ForEachClient(
delegate(IClientAPI client)
{

View File

@ -683,12 +683,10 @@ namespace OpenSim.Region.Framework.Scenes
itemCopy.SalePrice = item.SalePrice;
itemCopy.SaleType = item.SaleType;
if (AddInventoryItem(itemCopy))
{
IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
if (invAccess != null)
Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); });
}
IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
if (invAccess != null)
invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
AddInventoryItem(itemCopy);
if (!Permissions.BypassPermissions())
{

View File

@ -2895,11 +2895,14 @@ namespace OpenSim.Region.Framework.Scenes
public void PhysicsOutOfBounds(Vector3 pos)
{
m_log.Error("[PHYSICS]: Physical Object went out of bounds.");
// Note: This is only being called on the root prim at this time.
m_log.ErrorFormat(
"[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.",
Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition);
RemFlag(PrimFlags.Physics);
DoPhysicsPropertyUpdate(false, true);
//ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
}
public void PhysicsRequestingTerseUpdate()
@ -4549,7 +4552,7 @@ namespace OpenSim.Region.Framework.Scenes
if (ParentGroup.RootPart == this)
AngularVelocity = new Vector3(0, 0, 0);
}
else
else if (SetVD != wasVD)
{
if (ParentGroup.Scene.CollidablePrims)
{

View File

@ -214,8 +214,6 @@ namespace OpenSim.Region.Framework.Scenes
private Quaternion m_headrotation = Quaternion.Identity;
private string m_nextSitAnimation = String.Empty;
//PauPaw:Proper PID Controler for autopilot************
public bool MovingToTarget { get; private set; }
public Vector3 MoveToPositionTarget { get; private set; }
@ -2120,25 +2118,10 @@ namespace OpenSim.Region.Framework.Scenes
StandUp();
}
// if (!String.IsNullOrEmpty(sitAnimation))
// {
// m_nextSitAnimation = sitAnimation;
// }
// else
// {
m_nextSitAnimation = "SIT";
// }
//SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
SceneObjectPart part = FindNextAvailableSitTarget(targetID);
if (part != null)
{
if (!String.IsNullOrEmpty(part.SitAnimation))
{
m_nextSitAnimation = part.SitAnimation;
}
m_requestedSitTargetID = part.LocalId;
m_requestedSitTargetUUID = targetID;
@ -2352,18 +2335,6 @@ namespace OpenSim.Region.Framework.Scenes
*/
public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
{
if (!String.IsNullOrEmpty(m_nextSitAnimation))
{
HandleAgentSit(remoteClient, agentID, m_nextSitAnimation);
}
else
{
HandleAgentSit(remoteClient, agentID, "SIT");
}
}
public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation)
{
SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
@ -2436,7 +2407,12 @@ namespace OpenSim.Region.Framework.Scenes
Velocity = Vector3.Zero;
RemoveFromPhysicalScene();
String sitAnimation = "SIT";
if (!String.IsNullOrEmpty(part.SitAnimation))
{
sitAnimation = part.SitAnimation;
}
Animator.TrySetMovementAnimation(sitAnimation);
SendAvatarDataToAllAgents();
}

View File

@ -77,6 +77,26 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
}
[Test]
public void TestSetNonPhysicsVolumeDetectSinglePrim()
{
TestHelpers.InMethod();
m_scene.AddSceneObject(m_so1);
SceneObjectPart rootPart = m_so1.RootPart;
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
m_so1.ScriptSetVolumeDetect(true);
// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom));
m_so1.ScriptSetVolumeDetect(false);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
}
[Test]
public void TestSetPhysicsSinglePrim()
{
@ -89,13 +109,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests
m_so1.ScriptSetPhysicsStatus(true);
// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
m_so1.ScriptSetPhysicsStatus(false);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
}
[Test]
public void TestSetPhysicsVolumeDetectSinglePrim()
{
TestHelpers.InMethod();
m_scene.AddSceneObject(m_so1);
SceneObjectPart rootPart = m_so1.RootPart;
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
m_so1.ScriptSetPhysicsStatus(true);
m_so1.ScriptSetVolumeDetect(true);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics));
m_so1.ScriptSetVolumeDetect(false);
Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
}
[Test]
public void TestSetPhysicsLinkset()

View File

@ -105,12 +105,12 @@ public sealed class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
// do actual create at taint time
// do actual creation in taint time
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
{
DetailLog("{0},BSCharacter.create,taint", LocalID);
// New body and shape into PhysBody and PhysShape
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
SetPhysicalProperties();
});
@ -124,7 +124,9 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
{
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
PhysBody.Clear();
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
PhysShape.Clear();
});
}
@ -165,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Do this after the object has been added to the world
BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr,
(uint)CollisionFilterGroups.AvatarGroup,
(uint)CollisionFilterGroups.AvatarMask);
PhysBody.collisionType = CollisionType.Avatar;
PhysBody.ApplyCollisionMask();
}
public override void RequestPhysicsterseUpdate()
@ -187,6 +188,11 @@ public sealed class BSCharacter : BSPhysObject
set {
// When an avatar's size is set, only the height is changed.
_size = value;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
ComputeAvatarScale(_size);
ComputeAvatarVolumeAndMass();
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
@ -194,15 +200,18 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
{
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
UpdatePhysicalMassProperties(RawMass);
if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
{
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
UpdatePhysicalMassProperties(RawMass);
// Make sure this change appears as a property update event
BulletSimAPI.PushUpdate2(PhysBody.ptr);
}
});
}
}
public override OMV.Vector3 Scale { get; set; }
public override PrimitiveBaseShape Shape
{
set { BaseShape = value; }
@ -236,7 +245,8 @@ public sealed class BSCharacter : BSPhysObject
// Zero some other properties directly into the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
{
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
});
}
public override void ZeroAngularMotion(bool inTaintTime)
@ -245,10 +255,13 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
// The next also get rid of applied linear force but the linear velocity is untouched.
BulletSimAPI.ClearForces2(PhysBody.ptr);
if (PhysBody.HasPhysicalBody)
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
// The next also get rid of applied linear force but the linear velocity is untouched.
BulletSimAPI.ClearForces2(PhysBody.ptr);
}
});
}
@ -273,7 +286,8 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
{
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
}
}
@ -332,7 +346,8 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
{
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
});
ret = true;
}
@ -359,7 +374,8 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
{
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
}
@ -398,7 +414,8 @@ public sealed class BSCharacter : BSPhysObject
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
{
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
else
@ -406,7 +423,8 @@ public sealed class BSCharacter : BSPhysObject
if (_currentFriction != PhysicsScene.Params.avatarFriction)
{
_currentFriction = PhysicsScene.Params.avatarFriction;
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
_velocity = value;
@ -443,8 +461,11 @@ public sealed class BSCharacter : BSPhysObject
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
{
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
if (PhysBody.HasPhysicalBody)
{
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
});
}
}
@ -517,10 +538,13 @@ public sealed class BSCharacter : BSPhysObject
_floatOnWater = value;
PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
{
if (_floatOnWater)
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
else
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
if (PhysBody.HasPhysicalBody)
{
if (_floatOnWater)
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
else
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
}
});
}
}
@ -553,7 +577,8 @@ public sealed class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
}
}
@ -599,7 +624,8 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
{
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
else
@ -616,9 +642,6 @@ public sealed class BSCharacter : BSPhysObject
private void ComputeAvatarScale(OMV.Vector3 size)
{
// The 'size' given by the simulator is the mid-point of the avatar
// and X and Y are unspecified.
OMV.Vector3 newScale = size;
// newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
// newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;

View File

@ -57,7 +57,7 @@ public abstract class BSConstraint : IDisposable
if (m_enabled)
{
m_enabled = false;
if (m_constraint.ptr != IntPtr.Zero)
if (m_constraint.HasPhysicalConstraint)
{
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
@ -65,7 +65,7 @@ public abstract class BSConstraint : IDisposable
m_body1.ID, m_body1.ptr.ToString("X"),
m_body2.ID, m_body2.ptr.ToString("X"),
success);
m_constraint.ptr = System.IntPtr.Zero;
m_constraint.Clear();
}
}
}

View File

@ -65,7 +65,7 @@ public sealed class BSConstraint6Dof : BSConstraint
m_world = world;
m_body1 = obj1;
m_body2 = obj2;
if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
{
world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
BSScene.DetailLogZero, world.worldID,
@ -83,7 +83,7 @@ public sealed class BSConstraint6Dof : BSConstraint
world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
if (m_constraint.ptr == IntPtr.Zero)
if (!m_constraint.HasPhysicalConstraint)
{
world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
LogHeader, obj1.ID, obj2.ID);

View File

@ -570,8 +570,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
Prim.LocalID, friction, localInertia, angularDamping);
VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
}
else
{
@ -818,6 +818,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
+ hoverContribution
+ limitMotorUpContribution;
Vector3 newForce = buoyancyContribution;
// If not changing some axis, reduce out velocity
if ((m_flags & (VehicleFlag.NO_X)) != 0)
newVelocity.X = 0;
@ -845,7 +847,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
VehicleVelocity = newVelocity;
// Other linear forces are applied as forces.
Vector3 totalDownForce = buoyancyContribution * m_vehicleMass;
Vector3 totalDownForce = newForce * m_vehicleMass;
if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
{
VehicleAddForce(totalDownForce);
@ -991,8 +993,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
{
// If the vehicle is motoring into the sky, get it going back down.
float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition);
float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
float distanceAboveGround = VehiclePosition.Z - targetHeight;
// Not colliding if the vehicle is off the ground
if (!Prim.IsColliding)
{
@ -1005,8 +1007,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// has a decay factor. This says this force should
// be computed with a motor.
// TODO: add interaction with banking.
VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
Prim.LocalID, distanceAboveGround, ret);
VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
}
return ret;
}
@ -1055,7 +1057,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// TODO: Should this be applied as an angular force (torque)?
if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f))
{
Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep;
// DEBUG DEBUG DEBUG: optionally scale the angular velocity. Debugging SL vs ODE turning functions.
Vector3 scaledCorrection = m_lastAngularCorrection;
if (PhysicsScene.VehicleScaleAngularVelocityByTimestep)
scaledCorrection *= pTimestep;
VehicleRotationalVelocity = scaledCorrection;
VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}",

View File

@ -32,6 +32,14 @@ using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// A BSPrim can get individual information about its linkedness attached
// to it through an instance of a subclass of LinksetInfo.
// Each type of linkset will define the information needed for its type.
public abstract class BSLinksetInfo
{
}
public abstract class BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET]";
@ -116,7 +124,7 @@ public abstract class BSLinkset
get { return ComputeLinksetGeometricCenter(); }
}
protected void Initialize(BSScene scene, BSPhysObject parent)
protected BSLinkset(BSScene scene, BSPhysObject parent)
{
// A simple linkset of one (no children)
LinksetID = m_nextLinksetID++;
@ -127,6 +135,7 @@ public abstract class BSLinkset
LinksetRoot = parent;
m_children = new HashSet<BSPhysObject>();
m_mass = parent.RawMass;
Rebuilding = false;
}
// Link to a linkset where the child knows the parent.
@ -219,7 +228,7 @@ public abstract class BSLinkset
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPhysObject child);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@ -229,6 +238,10 @@ public abstract class BSLinkset
// May be called at runtime or taint-time.
public abstract void Refresh(BSPhysObject requestor);
// Flag denoting the linkset is in the process of being rebuilt.
// Used to know not the schedule a rebuild in the middle of a rebuild.
protected bool Rebuilding { get; set; }
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset

View File

@ -32,18 +32,43 @@ using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// When a child is linked, the relationship position of the child to the parent
// is remembered so the child's world position can be recomputed when it is
// removed from the linkset.
sealed class BSLinksetCompoundInfo : BSLinksetInfo
{
public OMV.Vector3 OffsetPos;
public OMV.Quaternion OffsetRot;
public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
{
OffsetPos = p;
OffsetRot = r;
}
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(OffsetPos.ToString());
buff.Append(",r=");
buff.Append(OffsetRot.ToString());
buff.Append(">");
return buff.ToString();
}
};
public sealed class BSLinksetCompound : BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
public BSLinksetCompound(BSScene scene, BSPhysObject parent)
public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
{
base.Initialize(scene, parent);
}
// For compound implimented linksets, if there are children, use compound shape for the root.
public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
{
// Returning 'unknown' means we don't have a preference.
BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
if (IsRoot(requestor) && HasAnyChildren)
{
@ -55,23 +80,27 @@ public sealed class BSLinksetCompound : BSLinkset
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPhysObject requestor)
{
// External request for Refresh (from BSPrim) doesn't need to do anything
// InternalRefresh(requestor);
}
// Schedule a refresh to happen after all the other taint processing.
private void InternalRefresh(BSPhysObject requestor)
{
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
// Queue to happen after all the other taint processing
PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}",
LinksetRoot.LocalID, requestor.LocalID, Rebuilding);
// When rebuilding, it is possible to set properties that would normally require a rebuild.
// If already rebuilding, don't request another rebuild.
if (!Rebuilding)
{
if (IsRoot(requestor) && HasAnyChildren)
RecomputeLinksetCompound();
});
PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
{
if (IsRoot(requestor) && HasAnyChildren)
RecomputeLinksetCompound();
});
}
}
// The object is going dynamic (physical). Do any setup necessary
@ -84,12 +113,24 @@ public sealed class BSLinksetCompound : BSLinkset
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
if (!IsRoot(child))
if (IsRoot(child))
{
// The root is going dynamic. Make sure mass is properly set.
m_mass = ComputeLinksetMass();
if (HasAnyChildren)
InternalRefresh(LinksetRoot);
}
else
{
// The origional prims are removed from the world as the shape of the root compound
// shape takes over.
BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
// We don't want collisions from the old linkset children.
BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
child.PhysBody.collisionType = CollisionType.LinksetChild;
ret = true;
}
return ret;
@ -104,11 +145,19 @@ public sealed class BSLinksetCompound : BSLinkset
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
if (!IsRoot(child))
if (IsRoot(child))
{
if (HasAnyChildren)
InternalRefresh(LinksetRoot);
}
else
{
// The non-physical children can come back to life.
BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
// Don't force activation so setting of DISABLE_SIMULATION can stay.
child.PhysBody.collisionType = CollisionType.LinksetChild;
// Don't force activation so setting of DISABLE_SIMULATION can stay if used.
BulletSimAPI.Activate2(child.PhysBody.ptr, false);
ret = true;
}
@ -146,20 +195,58 @@ public sealed class BSLinksetCompound : BSLinkset
if (!IsRoot(child))
{
// Cause the current shape to be freed and the new one to be built.
InternalRefresh(LinksetRoot);
ret = true;
// Because it is a convenient time, recompute child world position and rotation based on
// its position in the linkset.
RecomputeChildWorldPosition(child, true);
}
// Cannot schedule a refresh/rebuild here because this routine is called when
// the linkset is being rebuilt.
// InternalRefresh(LinksetRoot);
return ret;
}
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// this routine will restore the removed constraints.
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
// The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
}
// When the linkset is built, the child shape is added to the compound shape relative to the
// root shape. The linkset then moves around but this does not move the actual child
// prim. The child prim's location must be recomputed based on the location of the root shape.
private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
{
BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
if (lci != null)
{
if (inTaintTime)
{
OMV.Vector3 oldPos = child.RawPosition;
child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
child.LocalID, oldPos, lci, child.RawPosition);
}
else
{
// TaintedObject is not used here so the raw position is set now and not at taint-time.
child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
}
}
else
{
// This happens when children have been added to the linkset but the linkset
// has not been constructed yet. So like, at taint time, adding children to a linkset
// and then changing properties of the children (makePhysical, for instance)
// but the post-print action of actually rebuilding the linkset has not yet happened.
// PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
// LogHeader, child.LocalID);
DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
}
}
// ================================================================
@ -181,7 +268,7 @@ public sealed class BSLinksetCompound : BSLinkset
}
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
// Safe to call even if the child is not really in the linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
{
if (m_children.Remove(child))
@ -192,6 +279,7 @@ public sealed class BSLinksetCompound : BSLinkset
child.LocalID, child.PhysBody.ptr.ToString("X"));
// Cause the child's body to be rebuilt and thus restored to normal operation
RecomputeChildWorldPosition(child, false);
child.ForceBodyShapeRebuild(false);
if (!HasAnyChildren)
@ -215,59 +303,83 @@ public sealed class BSLinksetCompound : BSLinkset
// Called at taint time!!
private void RecomputeLinksetCompound()
{
// Cause the root shape to be rebuilt as a compound object with just the root in it
LinksetRoot.ForceBodyShapeRebuild(true);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
ForEachMember(delegate(BSPhysObject cPrim)
try
{
if (!IsRoot(cPrim))
// Suppress rebuilding while rebuilding
Rebuilding = true;
// Cause the root shape to be rebuilt as a compound object with just the root in it
LinksetRoot.ForceBodyShapeRebuild(true);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
ForEachMember(delegate(BSPhysObject cPrim)
{
// Each child position and rotation is given relative to the root.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
if (cPrim.PhysShape.isNativeShape)
if (!IsRoot(cPrim))
{
// Native shapes are not shared so we need to create a new one.
// A mesh or hull is created because scale is not available on a native shape.
// (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
}
else
{
// For the shared shapes (meshes and hulls), just use the shape in the child.
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
// Compute the displacement of the child from the root of the linkset.
// This info is saved in the child prim so the relationship does not
// change over time and the new child position can be computed
// when the linkset is being disassembled (the linkset may have moved).
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
if (lci == null)
{
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
// Each child position and rotation is given relative to the root.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
// Save relative position for recomputing child's world position after moving linkset.
lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
cPrim.LinksetInfo = lci;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
}
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
if (cPrim.PhysShape.isNativeShape)
{
// A native shape is turning into a hull collision shape because native
// shapes are not shared so we have to hullify it so it will be tracked
// and freed at the correct time. This also solves the scaling problem
// (native shapes scaled but hull/meshes are assumed to not be).
// TODO: decide of the native shape can just be used in the compound shape.
// Use call to CreateGeomNonSpecial().
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
}
else
{
// For the shared shapes (meshes and hulls), just use the shape in the child.
// The reference count added here will be decremented when the compound shape
// is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
{
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
}
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
}
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
}
}
return false; // 'false' says to move onto the next child in the list
});
// TODO: need to phantomize the child prims left behind.
// Maybe just destroy the children bodies and shapes and have them rebuild on unlink.
// Selection/deselection might cause way too many build/destructions esp. for LARGE linksets.
return false; // 'false' says to move onto the next child in the list
});
// With all of the linkset packed into the root prim, it has the mass of everyone.
float linksetMass = LinksetMass;
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
// With all of the linkset packed into the root prim, it has the mass of everyone.
float linksetMass = LinksetMass;
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
}
finally
{
Rebuilding = false;
}
BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);

View File

@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
{
base.Initialize(scene, parent);
}
// When physical properties are changed the linkset needs to recalculate

View File

@ -50,10 +50,11 @@ public struct MaterialAttributes
Avatar,
NumberOfTypes // the count of types in the enum.
}
// Names must be in the order of the above enum.
public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
"Flesh", "Plastic", "Rubber", "Light", "Avatar" };
public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
// These names must coorespond to the lower case field names in the MaterialAttributes
// structure as reflection is used to select the field to put the value in.
public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
public MaterialAttributes(string t, float d, float f, float r)
{
@ -70,60 +71,74 @@ public struct MaterialAttributes
public static class BSMaterials
{
public static MaterialAttributes[] Attributes;
// Attributes for each material type
private static readonly MaterialAttributes[] Attributes;
// Map of material name to material type code
public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
static BSMaterials()
{
// Attribute sets for both the non-physical and physical instances of materials.
Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
// Map of name to type code.
MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
MaterialMap.Add("Light", MaterialAttributes.Material.Light);
MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
}
// This is where all the default material attributes are defined.
public static void InitializeFromDefaults(ConfigurationParameters parms)
{
// Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
// public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
// "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
float dDensity = parms.defaultDensity;
float dFriction = parms.defaultFriction;
float dRestitution = parms.defaultRestitution;
float dDensity = parms.defaultDensity;
Attributes[(int)MaterialAttributes.Material.Stone] =
new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Metal] =
new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Glass] =
new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Wood] =
new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
Attributes[(int)MaterialAttributes.Material.Flesh] =
new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
Attributes[(int)MaterialAttributes.Material.Plastic] =
new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Rubber] =
new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
Attributes[(int)MaterialAttributes.Material.Light] =
new MaterialAttributes("light",dDensity, dFriction, dRestitution);
new MaterialAttributes("light",dDensity, dFriction, dRestitution);
Attributes[(int)MaterialAttributes.Material.Avatar] =
new MaterialAttributes("avatar",60f, 0.2f, 0f);
new MaterialAttributes("avatar",60f, 0.2f, 0f);
Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
}
// Under the [BulletSim] section, one can change the individual material
@ -139,34 +154,34 @@ public static class BSMaterials
// the physical value.
public static void InitializefromParameters(IConfig pConfig)
{
int matType = 0;
foreach (string matName in MaterialAttributes.MaterialNames)
foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
{
string matName = kvp.Key;
foreach (string attribName in MaterialAttributes.MaterialAttribs)
{
string paramName = matName + attribName;
if (pConfig.Contains(paramName))
{
float paramValue = pConfig.GetFloat(paramName);
SetAttributeValue(matType, attribName, paramValue);
SetAttributeValue((int)kvp.Value, attribName, paramValue);
// set the physical value also
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
}
paramName += "Physical";
if (pConfig.Contains(paramName))
{
float paramValue = pConfig.GetFloat(paramName);
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
}
}
matType++;
}
}
// Use reflection to set the value in the attribute structure.
private static void SetAttributeValue(int matType, string attribName, float val)
{
MaterialAttributes thisAttrib = Attributes[matType];
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
if (fieldInfo != null)
{
fieldInfo.SetValue(thisAttrib, val);
@ -174,12 +189,12 @@ public static class BSMaterials
}
}
// Given a material type, return a structure of attributes.
public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
{
int ind = (int)type;
if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
return Attributes[ind];
}
}
}

View File

@ -65,7 +65,7 @@ public abstract class BSMotor
// Can all the incremental stepping be replaced with motor classes?
// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
// The TargetValue is decays in TargetValueDecayTimeScale and
// The TargetValue decays in TargetValueDecayTimeScale and
// the CurrentValue will be held back by FrictionTimeScale.
// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.

View File

@ -60,6 +60,9 @@ public abstract class BSPhysObject : PhysicsActor
Linkset = BSLinkset.Factory(PhysicsScene, this);
LastAssetBuildFailed = false;
// Default material type
Material = MaterialAttributes.Material.Wood;
CollisionCollection = new CollisionEventUpdate();
SubscribedEventsMs = 0;
CollidingStep = 0;
@ -72,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor
public string TypeName { get; protected set; }
public BSLinkset Linkset { get; set; }
public BSLinksetInfo LinksetInfo { get; set; }
// Return the object mass without calculating it or having side effects
public abstract float RawMass { get; }
@ -105,10 +109,17 @@ public abstract class BSPhysObject : PhysicsActor
public EntityProperties CurrentEntityProperties { get; set; }
public EntityProperties LastEntityProperties { get; set; }
public abstract OMV.Vector3 Scale { get; set; }
public virtual OMV.Vector3 Scale { get; set; }
public abstract bool IsSolid { get; }
public abstract bool IsStatic { get; }
// Materialness
public MaterialAttributes.Material Material { get; private set; }
public override void SetMaterial(int material)
{
Material = (MaterialAttributes.Material)material;
}
// Stop all physical motion.
public abstract void ZeroMotion(bool inTaintTime);
public abstract void ZeroAngularMotion(bool inTaintTime);
@ -128,6 +139,17 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Quaternion RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { get; set; }
// The system is telling us the velocity it wants to move at.
protected OMV.Vector3 m_targetVelocity;
public override OMV.Vector3 TargetVelocity
{
get { return m_targetVelocity; }
set
{
m_targetVelocity = value;
Velocity = value;
}
}
public abstract OMV.Vector3 ForceVelocity { get; set; }
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@ -243,7 +265,9 @@ public abstract class BSPhysObject : PhysicsActor
SubscribedEventsMs = 0;
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
// Make sure there is a body there because sometimes destruction happens in an un-ideal order.
if (PhysBody.HasPhysicalBody)
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if the simulator wants collision events

View File

@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject
private static readonly string LogHeader = "[BULLETS PRIM]";
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
// Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
private bool _grabbed;
@ -93,7 +92,7 @@ public sealed class BSPrim : BSPhysObject
_physicsActorType = (int)ActorTypes.Prim;
_position = pos;
_size = size;
Scale = size; // the scale will be set by CreateGeom depending on object type
Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
_orientation = rotation;
_buoyancy = 1f;
_velocity = OMV.Vector3.Zero;
@ -108,8 +107,8 @@ public sealed class BSPrim : BSPhysObject
_mass = CalculateMass();
// No body or shape yet
PhysBody = new BulletBody(LocalID, IntPtr.Zero);
PhysShape = new BulletShape(IntPtr.Zero);
PhysBody = new BulletBody(LocalID);
PhysShape = new BulletShape();
DetailLog("{0},BSPrim.constructor,call", LocalID);
// do the actual object creation at taint time
@ -143,7 +142,9 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// If there are physical body and shape, release my use of same.
PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
PhysBody.Clear();
PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
PhysShape.Clear();
});
}
@ -157,12 +158,10 @@ public sealed class BSPrim : BSPhysObject
// We presume the scale and size are the same. If scale must be changed for
// the physical shape, that is done when the geometry is built.
_size = value;
Scale = _size;
ForceBodyShapeRebuild(false);
}
}
// Scale is what we set in the physics engine. It is different than 'size' in that
// 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
public override OMV.Vector3 Scale { get; set; }
public override PrimitiveBaseShape Shape {
set {
@ -189,7 +188,8 @@ public sealed class BSPrim : BSPhysObject
}
}
public override bool Selected {
set {
set
{
if (value != _isSelected)
{
_isSelected = value;
@ -247,7 +247,8 @@ public sealed class BSPrim : BSPhysObject
// Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ClearAllForces2(PhysBody.ptr);
});
}
public override void ZeroAngularMotion(bool inTaintTime)
@ -257,8 +258,11 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
// DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
if (PhysBody.HasPhysicalBody)
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
}
});
}
@ -295,8 +299,11 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
{
// DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
ActivateIfPhysical(false);
if (PhysBody.HasPhysicalBody)
{
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
ActivateIfPhysical(false);
}
});
}
}
@ -322,12 +329,12 @@ public sealed class BSPrim : BSPhysObject
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
OMV.Vector3 upForce = OMV.Vector3.Zero;
if (Position.Z < terrainHeight)
if (RawPosition.Z < terrainHeight)
{
DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
float targetHeight = terrainHeight + (Size.Z / 2f);
// Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
upForce.Z = (terrainHeight - Position.Z) * 1f;
upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
ret = true;
}
@ -335,10 +342,10 @@ public sealed class BSPrim : BSPhysObject
{
float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
// TODO: a floating motor so object will bob in the water
if (Math.Abs(Position.Z - waterHeight) > 0.1f)
if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
{
// Upforce proportional to the distance away from the water. Correct the error in 1 sec.
upForce.Z = (waterHeight - Position.Z) * 1f;
upForce.Z = (waterHeight - RawPosition.Z) * 1f;
ret = true;
}
}
@ -413,7 +420,8 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
{
// DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
});
}
}
@ -507,7 +515,8 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
{
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
});
}
}
@ -556,9 +565,12 @@ public sealed class BSPrim : BSPhysObject
// TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
{
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
// DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
if (PhysBody.HasPhysicalBody)
{
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
// DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
});
}
}
@ -649,14 +661,7 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Collision filter can be set only when the object is in the world
if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0)
{
if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask))
{
PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}",
LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask);
}
}
PhysBody.ApplyCollisionMask();
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
@ -683,8 +688,9 @@ public sealed class BSPrim : BSPhysObject
ZeroMotion(true);
// Set various physical properties so other object interact properly
BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
// Mass is zero which disables a bunch of physics stuff in Bullet
UpdatePhysicalMassProperties(0f);
@ -700,20 +706,21 @@ public sealed class BSPrim : BSPhysObject
// Start it out sleeping and physical actions could wake it up.
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
// This collides like a static object
PhysBody.collisionType = CollisionType.Static;
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
}
else
{
// Not a Bullet static object
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
// Set various physical properties so internal dynamic properties will get computed correctly as they are set
BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
// Set various physical properties so other object interact properly
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
// Since this can be called multiple times, only zero forces when becoming physical
@ -741,16 +748,15 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
// This collides like an object.
PhysBody.collisionType = CollisionType.Dynamic;
// Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
// BulletSimAPI.Activate2(BSBody.ptr, true);
PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
}
}
@ -777,8 +783,9 @@ public sealed class BSPrim : BSPhysObject
m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
}
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup;
PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
// Change collision info from a static object to a ghosty collision object
PhysBody.collisionType = CollisionType.VolumeDetect;
}
}
@ -861,7 +868,8 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
{
DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
});
}
}
@ -896,8 +904,11 @@ public sealed class BSPrim : BSPhysObject
_buoyancy = value;
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
if (PhysBody.HasPhysicalBody)
{
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
}
}
}
@ -965,7 +976,8 @@ public sealed class BSPrim : BSPhysObject
}
DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
if (fSum != OMV.Vector3.Zero)
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
});
}
@ -976,7 +988,8 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
{
DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
});
}
@ -1012,7 +1025,8 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
if (fSum != OMV.Vector3.Zero)
{
BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
_torque = fSum;
}
});
@ -1026,7 +1040,8 @@ public sealed class BSPrim : BSPhysObject
OMV.Vector3 applyImpulse = impulse;
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
{
BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
if (PhysBody.HasPhysicalBody)
BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
});
}
@ -1344,7 +1359,6 @@ public sealed class BSPrim : BSPhysObject
// Create the correct physical representation for this type of object.
// Updates PhysBody and PhysShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
// Returns 'true' if either the body or the shape was changed.
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
{
// Called if the current prim body is about to be destroyed.

View File

@ -188,6 +188,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private bool m_physicsLoggingDoFlush;
// 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; }
public bool VehiclePhysicalLoggingEnabled { get; private set; }
public bool VehicleScaleAngularVelocityByTimestep { get; private set; }
#region Construction and Initialization
public BSScene(string identifier)
@ -297,6 +299,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
// Very detailed logging for vehicle debugging
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
// Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
@ -306,6 +309,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
BSMaterials.InitializeFromDefaults(Params);
if (pConfig != null)
{
// Let the user add new and interesting material property values.
BSMaterials.InitializefromParameters(pConfig);
}
}
@ -501,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
try
{
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@ -510,7 +514,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
}
catch (Exception e)
{
@ -1226,6 +1230,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].vehicleAngularDamping; },
(s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
new ParameterDefn("VehicleScaleAngularVelocityByTimestep", "If true, scale angular turning by timestep",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.VehicleScaleAngularVelocityByTimestep = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.VehicleScaleAngularVelocityByTimestep); },
(s,p,l,v) => { s.VehicleScaleAngularVelocityByTimestep = s.BoolNumeric(v); } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f,

View File

@ -126,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable
return ret;
}
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim)
{
return GetBodyAndShape(forceRebuild, sim, prim, null, null);
}
// Track another user of a body.
// We presume the caller has allocated the body.
// Bodies only have one user so the body is just put into the world if not already there.
@ -149,7 +154,7 @@ public sealed class BSShapeCollection : IDisposable
// Called when releasing use of a BSBody. BSShape is handled separately.
public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
{
if (body.ptr == IntPtr.Zero)
if (!body.HasPhysicalBody)
return;
lock (m_collectionActivityLock)
@ -243,12 +248,12 @@ public sealed class BSShapeCollection : IDisposable
// Release the usage of a shape.
public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
{
if (shape.ptr == IntPtr.Zero)
if (!shape.HasPhysicalShape)
return;
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
{
if (shape.ptr != IntPtr.Zero)
if (shape.HasPhysicalShape)
{
if (shape.isNativeShape)
{
@ -440,7 +445,7 @@ public sealed class BSShapeCollection : IDisposable
}
// Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
bool haveShape = false;
@ -460,6 +465,11 @@ public sealed class BSShapeCollection : IDisposable
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
{
// Get the scale of any existing shape so we can see if the new shape is same native type and same size.
OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
if (prim.PhysShape.HasPhysicalShape)
scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr);
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
@ -469,7 +479,7 @@ public sealed class BSShapeCollection : IDisposable
{
haveShape = true;
if (forceRebuild
|| prim.Scale != prim.Size
|| prim.Scale != scaleOfExistingShape
|| prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
)
{
@ -483,7 +493,7 @@ public sealed class BSShapeCollection : IDisposable
{
haveShape = true;
if (forceRebuild
|| prim.Scale != prim.Size
|| prim.Scale != scaleOfExistingShape
|| prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
)
{
@ -542,7 +552,6 @@ public sealed class BSShapeCollection : IDisposable
prim.LocalID, newShape, prim.Scale);
// native shapes are scaled by Bullet
prim.Scale = prim.Size;
prim.PhysShape = newShape;
return true;
}
@ -555,8 +564,8 @@ public sealed class BSShapeCollection : IDisposable
ShapeData nativeShapeData = new ShapeData();
nativeShapeData.Type = shapeType;
nativeShapeData.ID = prim.LocalID;
nativeShapeData.Scale = prim.Size;
nativeShapeData.Size = prim.Size; // unneeded, I think.
nativeShapeData.Scale = prim.Scale;
nativeShapeData.Size = prim.Scale; // unneeded, I think.
nativeShapeData.MeshKey = (ulong)shapeKey;
nativeShapeData.HullKey = (ulong)shapeKey;
@ -573,7 +582,7 @@ public sealed class BSShapeCollection : IDisposable
// Native shapes are scaled in Bullet so set the scaling to the size
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
}
if (newShape.ptr == IntPtr.Zero)
if (!newShape.HasPhysicalShape)
{
PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
LogHeader, prim.LocalID, shapeType);
@ -590,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable
// Called at taint-time!
private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{
BulletShape newShape = new BulletShape(IntPtr.Zero);
BulletShape newShape = new BulletShape();
float lod;
System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@ -611,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable
ReferenceShape(newShape);
// meshes are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.PhysShape = newShape;
return true; // 'true' means a new shape has been added to this prim
@ -683,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable
ReferenceShape(newShape);
// hulls are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.PhysShape = newShape;
return true; // 'true' means a new shape has been added to this prim
}
@ -793,7 +798,7 @@ public sealed class BSShapeCollection : IDisposable
BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
newShape.shapeKey = newHullKey;
return newShape; // 'true' means a new shape has been added to this prim
return newShape;
}
// Callback from convex hull creater with a newly created hull.
@ -860,7 +865,7 @@ public sealed class BSShapeCollection : IDisposable
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
{
// If the shape was successfully created, nothing more to do
if (newShape.ptr != IntPtr.Zero)
if (newShape.HasPhysicalShape)
return newShape;
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@ -919,7 +924,7 @@ public sealed class BSShapeCollection : IDisposable
bool ret = false;
// the mesh, hull or native shape must have already been created in Bullet
bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
// If there is an existing body, verify it's of an acceptable type.
// If not a solid object, body is a GhostObject. Otherwise a RigidBody.

View File

@ -121,9 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
// redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask);
m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
m_mapInfo.terrainBody.ApplyCollisionMask();
// Make it so the terrain will not move or be considered for movement.
BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@ -136,7 +135,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
{
if (m_mapInfo != null)
{
if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
if (m_mapInfo.terrainBody.HasPhysicalBody)
{
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
// Frees both the body and the shape.

View File

@ -140,8 +140,8 @@ public sealed class BSTerrainManager
// Ground plane does not move
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
// Everything collides with the ground plane.
BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask);
m_groundPlane.collisionType = CollisionType.Groundplane;
m_groundPlane.ApplyCollisionMask();
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@ -151,13 +151,13 @@ public sealed class BSTerrainManager
// Release all the terrain structures we might have allocated
public void ReleaseGroundPlaneAndTerrain()
{
if (m_groundPlane.ptr != IntPtr.Zero)
if (m_groundPlane.HasPhysicalBody)
{
if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
{
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
}
m_groundPlane.ptr = IntPtr.Zero;
m_groundPlane.Clear();
}
ReleaseTerrain();

View File

@ -94,7 +94,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
indicesCount, indices, verticesCount, vertices),
BSPhysicsShapeType.SHAPE_MESH);
if (m_terrainShape.ptr == IntPtr.Zero)
if (!m_terrainShape.HasPhysicalShape)
{
// DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@ -107,7 +107,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
Quaternion rot = Quaternion.Identity;
m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
if (m_terrainBody.ptr == IntPtr.Zero)
if (!m_terrainBody.HasPhysicalBody)
{
// DISASTER!!
physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@ -130,9 +130,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask);
m_terrainBody.collisionType = CollisionType.Terrain;
m_terrainBody.ApplyCollisionMask();
// Make it so the terrain will not move or be considered for movement.
BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@ -140,7 +139,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
public override void Dispose()
{
if (m_terrainBody.ptr != IntPtr.Zero)
if (m_terrainBody.HasPhysicalBody)
{
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
// Frees both the body and the shape.

View File

@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
@ -32,93 +33,6 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API
// These hold pointers to allocated objects in the unmanaged space.
// The physics engine controller class created at initialization
public struct BulletSim
{
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
{
ptr = xx;
worldID = worldId;
physicsScene = bss;
}
public IntPtr ptr;
public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene physicsScene;
}
// An allocated Bullet btRigidBody
public struct BulletBody
{
public BulletBody(uint id, IntPtr xx)
{
ID = id;
ptr = xx;
collisionGroup = 0;
collisionMask = 0;
}
public IntPtr ptr;
public uint ID;
public CollisionFilterGroups collisionGroup;
public CollisionFilterGroups collisionMask;
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<id=");
buff.Append(ID.ToString());
buff.Append(",p=");
buff.Append(ptr.ToString("X"));
if (collisionGroup != 0 || collisionMask != 0)
{
buff.Append(",g=");
buff.Append(collisionGroup.ToString("X"));
buff.Append(",m=");
buff.Append(collisionMask.ToString("X"));
}
buff.Append(">");
return buff.ToString();
}
}
public struct BulletShape
{
public BulletShape(IntPtr xx)
{
ptr = xx;
type=BSPhysicsShapeType.SHAPE_UNKNOWN;
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
isNativeShape = false;
}
public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
{
ptr = xx;
type = typ;
shapeKey = 0;
isNativeShape = false;
}
public IntPtr ptr;
public BSPhysicsShapeType type;
public System.UInt64 shapeKey;
public bool isNativeShape;
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(shapeKey.ToString("X"));
buff.Append(",n=");
buff.Append(isNativeShape.ToString());
buff.Append(">");
return buff.ToString();
}
}
// Constraint type values as defined by Bullet
public enum ConstraintType : int
{
@ -132,44 +46,6 @@ public enum ConstraintType : int
MAX_CONSTRAINT_TYPE
}
// An allocated Bullet btConstraint
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx)
{
ptr = xx;
}
public IntPtr ptr;
}
// An allocated HeightMapThing which holds various heightmap info.
// Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather
// than making copies.
public class BulletHeightMapInfo
{
public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx;
heightMap = hm;
terrainRegionBase = Vector3.Zero;
minCoords = new Vector3(100f, 100f, 25f);
maxCoords = new Vector3(101f, 101f, 26f);
minZ = maxZ = 0f;
sizeX = sizeY = 256f;
}
public uint ID;
public IntPtr Ptr;
public float[] heightMap;
public Vector3 terrainRegionBase;
public Vector3 minCoords;
public Vector3 maxCoords;
public float sizeX, sizeY;
public float minZ, maxZ;
public BulletShape terrainShape;
public BulletBody terrainBody;
}
// ===============================================================================
[StructLayout(LayoutKind.Sequential)]
public struct ConvexHull
@ -362,21 +238,15 @@ public enum CollisionFlags : uint
BS_FLOATS_ON_WATER = 1 << 11,
BS_VEHICLE_COLLISIONS = 1 << 12,
BS_NONE = 0,
BS_ALL = 0xFFFFFFFF,
// These are the collision flags switched depending on physical state.
// The other flags are used for other things and should not be fooled with.
BS_ACTIVE = CF_STATIC_OBJECT
| CF_KINEMATIC_OBJECT
| CF_NO_CONTACT_RESPONSE
BS_ALL = 0xFFFFFFFF
};
// Values for collisions groups and masks
// Values f collisions groups and masks
public enum CollisionFilterGroups : uint
{
// Don't use the bit definitions!! Define the use in a
// filter/mask definition below. This way collision interactions
// are more easily debugged.
// are more easily found and debugged.
BNoneGroup = 0,
BDefaultGroup = 1 << 0,
BStaticGroup = 1 << 1,
@ -390,24 +260,8 @@ public enum CollisionFilterGroups : uint
BTerrainGroup = 1 << 11,
BRaycastGroup = 1 << 12,
BSolidGroup = 1 << 13,
BLinksetGroup = 1 << 14,
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarGroup = BCharacterGroup,
AvatarMask = BAllGroup,
ObjectGroup = BSolidGroup,
ObjectMask = BAllGroup,
StaticObjectGroup = BStaticGroup,
StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
LinksetGroup = BLinksetGroup,
LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other
VolumeDetectGroup = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainGroup = BTerrainGroup,
TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
GroundPlaneGroup = BGroundPlaneGroup,
GroundPlaneMask = BAllGroup
// BLinksetGroup = xx // a linkset proper is either static or dynamic
BLinksetChildGroup = 1 << 14,
};
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@ -434,7 +288,7 @@ public enum ConstraintParamAxis : int
// ===============================================================================
static class BulletSimAPI {
// ===============================================================================
// Link back to the managed code for outputting log messages
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);

View File

@ -0,0 +1,278 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// Classes to allow some type checking for the API
// These hold pointers to allocated objects in the unmanaged space.
// The physics engine controller class created at initialization
public struct BulletSim
{
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
{
ptr = xx;
worldID = worldId;
physicsScene = bss;
}
public IntPtr ptr;
public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene physicsScene;
}
// An allocated Bullet btRigidBody
public struct BulletBody
{
public BulletBody(uint id) : this(id, IntPtr.Zero)
{
}
public BulletBody(uint id, IntPtr xx)
{
ID = id;
ptr = xx;
collisionType = CollisionType.Static;
}
public IntPtr ptr;
public uint ID;
public CollisionType collisionType;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } }
// Apply the specificed collision mask into the physical world
public void ApplyCollisionMask()
{
// Should assert the body has been added to the physical world.
// (The collision masks are stored in the collision proxy cache which only exists for
// a collision body that is in the world.)
BulletSimAPI.SetCollisionGroupMask2(ptr,
BulletSimData.CollisionTypeMasks[collisionType].group,
BulletSimData.CollisionTypeMasks[collisionType].mask);
}
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<id=");
buff.Append(ID.ToString());
buff.Append(",p=");
buff.Append(ptr.ToString("X"));
buff.Append(",c=");
buff.Append(collisionType);
buff.Append(">");
return buff.ToString();
}
}
public struct BulletShape
{
public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
{
}
public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
{
ptr = xx;
type = typ;
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
isNativeShape = false;
}
public IntPtr ptr;
public BSPhysicsShapeType type;
public System.UInt64 shapeKey;
public bool isNativeShape;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } }
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(shapeKey.ToString("X"));
buff.Append(",n=");
buff.Append(isNativeShape.ToString());
buff.Append(">");
return buff.ToString();
}
}
// An allocated Bullet btConstraint
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx)
{
ptr = xx;
}
public IntPtr ptr;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
}
// An allocated HeightMapThing which holds various heightmap info.
// Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather
// than making copies.
public class BulletHeightMapInfo
{
public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx;
heightMap = hm;
terrainRegionBase = OMV.Vector3.Zero;
minCoords = new OMV.Vector3(100f, 100f, 25f);
maxCoords = new OMV.Vector3(101f, 101f, 26f);
minZ = maxZ = 0f;
sizeX = sizeY = 256f;
}
public uint ID;
public IntPtr Ptr;
public float[] heightMap;
public OMV.Vector3 terrainRegionBase;
public OMV.Vector3 minCoords;
public OMV.Vector3 maxCoords;
public float sizeX, sizeY;
public float minZ, maxZ;
public BulletShape terrainShape;
public BulletBody terrainBody;
}
// The general class of collsion object.
public enum CollisionType
{
Avatar,
Groundplane,
Terrain,
Static,
Dynamic,
VolumeDetect,
// Linkset, // A linkset should be either Static or Dynamic
LinksetChild,
Unknown
};
// Hold specification of group and mask collision flags for a CollisionType
public struct CollisionTypeFilterGroup
{
public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
{
type = t;
group = g;
mask = m;
}
public CollisionType type;
public uint group;
public uint mask;
};
/* NOTE: old definitions kept for reference. Delete when things are working.
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarGroup = BCharacterGroup,
AvatarMask = BAllGroup,
ObjectGroup = BSolidGroup,
ObjectMask = BAllGroup,
StaticObjectGroup = BStaticGroup,
StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
LinksetGroup = BLinksetGroup,
LinksetMask = BAllGroup,
LinksetChildGroup = BLinksetChildGroup,
LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
VolumeDetectGroup = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainGroup = BTerrainGroup,
TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
GroundPlaneGroup = BGroundPlaneGroup,
GroundPlaneMask = BAllGroup
*/
public static class BulletSimData
{
// Map of collisionTypes to flags for collision groups and masks.
// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
// but, instead, use references to this dictionary. Finding and debugging
// collision flag problems will be made easier.
public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
= new Dictionary<CollisionType, CollisionTypeFilterGroup>()
{
{ CollisionType.Avatar,
new CollisionTypeFilterGroup(CollisionType.Avatar,
(uint)CollisionFilterGroups.BCharacterGroup,
(uint)CollisionFilterGroups.BAllGroup)
},
{ CollisionType.Groundplane,
new CollisionTypeFilterGroup(CollisionType.Groundplane,
(uint)CollisionFilterGroups.BGroundPlaneGroup,
(uint)CollisionFilterGroups.BAllGroup)
},
{ CollisionType.Terrain,
new CollisionTypeFilterGroup(CollisionType.Terrain,
(uint)CollisionFilterGroups.BTerrainGroup,
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
},
{ CollisionType.Static,
new CollisionTypeFilterGroup(CollisionType.Static,
(uint)CollisionFilterGroups.BStaticGroup,
(uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
},
{ CollisionType.Dynamic,
new CollisionTypeFilterGroup(CollisionType.Dynamic,
(uint)CollisionFilterGroups.BSolidGroup,
(uint)(CollisionFilterGroups.BAllGroup))
},
{ CollisionType.VolumeDetect,
new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
(uint)CollisionFilterGroups.BSensorTrigger,
(uint)(~CollisionFilterGroups.BSensorTrigger))
},
{ CollisionType.LinksetChild,
new CollisionTypeFilterGroup(CollisionType.LinksetChild,
(uint)CollisionFilterGroups.BTerrainGroup,
(uint)(CollisionFilterGroups.BNoneGroup))
},
};
}
}

View File

@ -11,13 +11,20 @@ CRASHES
VEHICLES TODO LIST:
=================================================
Neb car jiggling left and right
Happens on terrain and any other mesh object. Flat cubes are much smoother.
Neb vehicle taking > 25ms of physics time!!
Vehicles (Move smoothly)
Add vehicle collisions so IsColliding is properly reported.
Needed for banking, limitMotorUp, movementLimiting, ...
Some vehicles should not be able to turn if no speed or off ground.
Neb car jiggling left and right
Happens on terrain and any other mesh object. Flat cubes are much smoother.
This has been reduced but not eliminated.
Light cycle falling over when driving
For limitMotorUp, use raycast down to find if vehicle is in the air.
Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
Verify that angular motion specified around Z moves in the vehicle coordinates.
Verify llGetVel() is returning a smooth and good value for vehicle movement.
llGetVel() should return the root's velocity if requested in a child prim.
Implement function efficiency for lineaar and angular motion.
Should vehicle angular/linear movement friction happen after all the components
or does it only apply to the basic movement?
@ -30,15 +37,14 @@ Border crossing with linked vehicle causes crash
BULLETSIM TODO LIST:
=================================================
Avatar height off after unsitting (floats off ground)
Editting appearance then moving restores.
Must not be initializing height when recreating capsule after unsit.
Duplicating a physical prim causes old prim to jump away
Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
Disable activity of passive linkset children.
Since the linkset is a compound object, the old prims are left lying
around and need to be phantomized so they don't collide, ...
Scenes with hundred of thousands of static objects take a lot of physics CPU time.
BSPrim.Force should set a continious force on the prim. The force should be
applied each tick. Some limits?
Single prim vehicles don't seem to properly vehiclize.
Gun sending shooter flying.
Collision margin (gap between physical objects lying on each other)
Boundry checking (crashes related to crossing boundry)
@ -51,14 +57,34 @@ Small physical objects do not interact correctly
The chain will fall apart and pairs will dance around on ground
Chains of 1x1x.2 will stay connected but will dance.
Chains above 2x2x.4 are move stable and get stablier as torui get larger.
Add material type linkage and input all the material property definitions.
Skeleton classes and table are in the sources but are not filled or used.
Add PID motor for avatar movement (slow to stop, ...)
setForce should set a constant force. Different than AddImpulse.
Implement raycast.
Implement ShapeCollection.Dispose()
Implement water as a plain so raycasting and collisions can happen with same.
Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
Also osGetPhysicsEngineVerion() maybe.
LINKSETS
======================================================
Linksets should allow collisions to individual children
Add LocalID to children shapes in LinksetCompound and create events for individuals
Verify/think through scripts in children of linksets. What do they reference
and return when getting position, velocity, ...
Confirm constraint linksets still work after making all the changes for compound linksets.
Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
For compound linksets, add ability to remove or reposition individual child shapes.
Disable activity of passive linkset children.
Since the linkset is a compound object, the old prims are left lying
around and need to be phantomized so they don't collide, ...
Speed up creation of large physical linksets
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
Eliminate collisions between objects in a linkset. (LinksetConstraint)
Have UserPointer point to struct with localID and linksetID?
Objects in original linkset still collide with each other?
MORE
======================================================
Find/remove avatar collision with ID=0.
Test avatar walking up stairs. How does compare with SL.
Radius of the capsule affects ability to climb edges.
@ -67,8 +93,6 @@ Debounce avatar contact so legs don't keep folding up when standing.
Implement LSL physics controls. Like STATUS_ROTATE_X.
Add border extensions to terrain to help region crossings and objects leaving region.
Speed up creation of large physical linksets
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
Performance test with lots of avatars. Can BulletSim support a thousand?
Optimize collisions in C++: only send up to the object subscribed to collisions.
Use collision subscription and remove the collsion(A,B) and collision(B,A)
@ -79,10 +103,6 @@ Avatar jump
Performance measurement and changes to make quicker.
Implement detailed physics stats (GetStats()).
Eliminate collisions between objects in a linkset. (LinksetConstraint)
Have UserPointer point to struct with localID and linksetID?
Objects in original linkset still collide with each other?
Measure performance improvement from hulls
Test not using ghost objects for volume detect implementation.
Performance of closures and delegates for taint processing
@ -95,10 +115,16 @@ Physics Arena central pyramid: why is one side permiable?
INTERNAL IMPROVEMENT/CLEANUP
=================================================
Consider moving prim/character body and shape destruction in destroy()
to postTimeTime rather than protecting all the potential sets that
might have been queued up.
Remove unused fields from ShapeData (not used in API2)
Breakout code for mesh/hull/compound/native into separate BSShape* classes
Standardize access to building and reference code.
The skeleton classes are in the sources but are not complete or linked in.
Make BSBody and BSShape real classes to centralize creation/changin/destruction
Convert state and parameter calls from BulletSimAPI direct calls to
calls on BSBody and BSShape
Generalize Dynamics and PID with standardized motors.
Generalize Linkset and vehicles into PropertyManagers
Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
@ -110,7 +136,7 @@ Implement linkset by setting position of children when root updated. (LinksetMan
Linkset implementation using manual prim movement.
LinkablePrim class? Would that simplify/centralize the linkset logic?
BSScene.UpdateParameterSet() is broken. How to set params on objects?
Remove HeightmapInfo from terrain specification.
Remove HeightmapInfo from terrain specification
Since C++ code does not need terrain height, this structure et al are not needed.
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
bob at the water level. BSPrim.PositionSanityCheck().
@ -142,7 +168,11 @@ Do prim hash codes work for sculpties and meshes? (Resolution: yes)
Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
Compound shapes will need the LocalID in the shapes and collision
processing to get it from there.
Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
Package Bullet source mods for Bullet internal stats output
(Resolution: move code into WorldData.h rather than relying on patches)
(Resolution: move code into WorldData.h rather than relying on patches)
Single prim vehicles don't seem to properly vehiclize.
(Resolution: mass was not getting set properly for single prim linksets)
Add material type linkage and input all the material property definitions.
Skeleton classes and table are in the sources but are not filled or used.
(Resolution:

View File

@ -333,17 +333,20 @@ namespace OpenSim.Region.Physics.Manager
}
/// <summary>
/// Velocity of this actor.
/// The desired velocity of this actor.
/// </summary>
/// <remarks>
/// Setting this provides a target velocity for physics scene updates.
/// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity,
/// time to accelerate and collisions.
/// Getting this returns the last set target. Fetch Velocity to get the current velocity.
/// </remarks>
protected Vector3 m_targetVelocity;
public virtual Vector3 TargetVelocity
{
get { return Velocity; }
set { Velocity = value; }
get { return m_targetVelocity; }
set {
m_targetVelocity = value;
Velocity = m_targetVelocity;
}
}
public abstract Vector3 Velocity { get; set; }

View File

@ -58,6 +58,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
/// </summary>
public interface IScriptInstance
{
/// <summary>
/// Debug level for this script instance.
/// </summary>
/// <remarks>
/// Level == 0, no extra data is logged.
/// Level >= 1, state changes are logged.
/// Level >= 2, event firing is logged.
/// <value>
/// The debug level.
/// </value>
int DebugLevel { get; set; }
/// <summary>
/// Is the script currently running?
/// </summary>

View File

@ -94,6 +94,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
private UUID m_CurrentStateHash;
private UUID m_RegionID;
public int DebugLevel { get; set; }
public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; }
private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
@ -549,9 +551,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// forcibly abort the work item (this aborts the underlying thread).
if (!m_InSelfDelete)
{
// m_log.ErrorFormat(
// "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}",
// ScriptName, ItemID, PrimName, ObjectID, m_InSelfDelete, DateTime.Now.Ticks);
m_log.DebugFormat(
"[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms",
ScriptName, ItemID, PrimName, LocalID, timeout);
workItem.Abort();
}
@ -707,19 +709,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
if (DebugLevel >= 2)
m_log.DebugFormat(
"[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
data.EventName,
ScriptName,
part.Name,
part.LocalId,
part.ParentGroup.Name,
part.ParentGroup.UUID,
part.AbsolutePosition,
part.ParentGroup.Scene.Name);
m_DetectParams = data.DetectParams;
if (data.EventName == "state") // Hardcoded state change
{
// m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}",
// PrimName, ScriptName, data.Params[0].ToString());
State = data.Params[0].ToString();
if (DebugLevel >= 1)
m_log.DebugFormat(
"[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
State,
ScriptName,
part.Name,
part.LocalId,
part.ParentGroup.Name,
part.ParentGroup.UUID,
part.AbsolutePosition,
part.ParentGroup.Scene.Name);
AsyncCommandManager.RemoveScript(Engine,
LocalID, ItemID);
SceneObjectPart part = Engine.World.GetSceneObjectPart(
LocalID);
if (part != null)
{
part.SetScriptEvents(ItemID,
@ -731,8 +755,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (Engine.World.PipeEventsForScript(LocalID) ||
data.EventName == "control") // Don't freeze avies!
{
SceneObjectPart part = Engine.World.GetSceneObjectPart(
LocalID);
// m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
// PrimName, ScriptName, data.EventName, State);

View File

@ -108,6 +108,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private IXmlRpcRouter m_XmlRpcRouter;
private int m_EventLimit;
private bool m_KillTimedOutScripts;
/// <summary>
/// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
/// its thread.
/// </summary>
/// <remarks>
/// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
/// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
/// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
/// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
/// actually hold.
///
/// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
/// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
/// shutting down.
/// </remarks>
private int m_WaitForEventCompletionOnScriptStop = 1000;
private string m_ScriptEnginesPath = null;
private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
@ -317,6 +335,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
m_WaitForEventCompletionOnScriptStop
= m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
m_Prio = ThreadPriority.BelowNormal;
@ -372,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
MainConsole.Instance.Commands.AddCommand(
"Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information",
"Show information on all scripts known to the script engine."
"Show information on all scripts known to the script engine.\n"
+ "If a <script-item-uuid> is given then only information on that script will be shown.",
HandleShowScripts);
@ -391,22 +412,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine
MainConsole.Instance.Commands.AddCommand(
"Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts",
"Resumes all currently suspended scripts.\n"
+ "Resumed scripts will process all events accumulated whilst suspended."
+ "Resumed scripts will process all events accumulated whilst suspended.\n"
+ "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
MainConsole.Instance.Commands.AddCommand(
"Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts",
"Stops all running scripts."
"Stops all running scripts.\n"
+ "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
MainConsole.Instance.Commands.AddCommand(
"Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts",
"Starts all stopped scripts."
"Starts all stopped scripts.\n"
+ "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
(module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
MainConsole.Instance.Commands.AddCommand(
"Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
"Activates or deactivates extra debug logging for the given script.\n"
+ "Level == 0, deactivate extra debug logging.\n"
+ "Level >= 1, log state changes.\n"
+ "Level >= 2, log event invocations.\n",
HandleDebugScriptLogCommand);
// MainConsole.Instance.Commands.AddCommand(
// "Debug", false, "debug xengine", "debug xengine [<level>]",
// "Turn on detailed xengine debugging.",
@ -415,6 +444,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
// HandleDebugLevelCommand);
}
private void HandleDebugScriptLogCommand(string module, string[] args)
{
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
return;
if (args.Length != 5)
{
MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
return;
}
UUID itemId;
if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
return;
int newLevel;
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
return;
IScriptInstance si;
lock (m_Scripts)
{
// XXX: We can't give the user feedback on a bad item id because this may apply to a different script
// engine
if (!m_Scripts.TryGetValue(itemId, out si))
return;
}
si.DebugLevel = newLevel;
MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
}
/// <summary>
/// Change debug level
/// </summary>
@ -486,7 +550,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (!UUID.TryParse(rawItemId, out itemId))
{
MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId);
MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
return;
}
@ -610,6 +674,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@ -1375,9 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
lockScriptsForWrite(false);
instance.ClearQueue();
// Give the script some time to finish processing its last event. Simply aborting the script thread can
// cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
instance.Stop(1000);
instance.Stop(m_WaitForEventCompletionOnScriptStop);
// bool objectRemoved = false;
@ -1735,16 +1798,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
public void StopScript(UUID itemID)
{
IScriptInstance instance = GetInstance(itemID);
if (instance != null)
{
// Give the script some time to finish processing its last event. Simply aborting the script thread can
// cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
instance.Stop(1000);
}
instance.Stop(m_WaitForEventCompletionOnScriptStop);
else
{
m_runFlags.AddOrUpdate(itemID, false, 240);
}
}
public DetectParams GetDetectParams(UUID itemID, int idx)

View File

@ -94,8 +94,6 @@ namespace OpenSim.Region.UserStatistics
if (!enabled)
return;
AddEventHandlers();
if (Util.IsWindows())
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
@ -143,10 +141,14 @@ namespace OpenSim.Region.UserStatistics
lock (m_scenes)
{
m_scenes.Add(scene);
if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID))
m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
updateLogMod = m_scenes.Count * 2;
m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
scene.EventManager.OnClientClosed += OnClientClosed;
scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
}
}
@ -157,6 +159,15 @@ namespace OpenSim.Region.UserStatistics
public void RemoveRegion(Scene scene)
{
if (!enabled)
return;
lock (m_scenes)
{
m_scenes.Remove(scene);
updateLogMod = m_scenes.Count * 2;
m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
}
}
public virtual void Close()
@ -187,9 +198,7 @@ namespace OpenSim.Region.UserStatistics
private void ReceiveClassicSimStatsPacket(SimStats stats)
{
if (!enabled)
{
return;
}
try
{
@ -198,17 +207,25 @@ namespace OpenSim.Region.UserStatistics
if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
return;
if ((updateLogCounter++ % updateLogMod) == 0)
// We will conduct this under lock so that fields such as updateLogCounter do not potentially get
// confused if a scene is removed.
// XXX: Possibly the scope of this lock could be reduced though it's not critical.
lock (m_scenes)
{
m_loglines = readLogLines(10);
if (updateLogCounter > 10000) updateLogCounter = 1;
}
if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
{
m_loglines = readLogLines(10);
USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
if (updateLogCounter > 10000)
updateLogCounter = 1;
}
if ((++ss.StatsCounter % updateStatsMod) == 0)
{
ss.ConsumeSimStats(stats);
USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
if ((++ss.StatsCounter % updateStatsMod) == 0)
{
ss.ConsumeSimStats(stats);
}
}
}
catch (KeyNotFoundException)

View File

@ -89,12 +89,39 @@ namespace OpenSim.Server.Base
Config = config;
Registry = new AddinRegistry(registryPath, ".");
suppress_console_output_(true);
AddinManager.Initialize(registryPath);
suppress_console_output_(false);
AddinManager.Registry.Update();
CommandManager commandmanager = new CommandManager(Registry);
AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged);
}
private static TextWriter prev_console_;
// Temporarily masking the errors reported on start
// This is caused by a non-managed dll in the ./bin dir
// when the registry is initialized. The dll belongs to
// libomv, which has a hard-coded path to "." for pinvoke
// to load the openjpeg dll
//
// Will look for a way to fix, but for now this keeps the
// confusion to a minimum. this was copied from our region
// plugin loader, we have been doing this in there for a long time.
//
public void suppress_console_output_(bool save)
{
if (save)
{
prev_console_ = System.Console.Out;
System.Console.SetOut(new StreamWriter(Stream.Null));
}
else
{
if (prev_console_ != null)
System.Console.SetOut(prev_console_);
}
}
private void OnExtensionChanged(object s, ExtensionNodeEventArgs args)
{
IRobustConnector connector = (IRobustConnector)args.ExtensionObject;
@ -112,8 +139,7 @@ namespace OpenSim.Server.Base
if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
{
m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name);
connector.PluginPath = String.Format("{0}/{1}", Registry.DefaultAddinsFolder, a.Name.Replace(',', '.'));
}
connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
else
{
m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name);
@ -189,20 +215,30 @@ namespace OpenSim.Server.Base
/// <param name="dllName"></param>
/// <param name="args">The arguments which control which constructor is invoked on the plugin</param>
/// <returns></returns>
public static T LoadPlugin<T>(string dllName, Object[] args) where T:class
public static T LoadPlugin<T> (string dllName, Object[] args) where T:class
{
// This is good to debug configuration problems
//if (dllName == string.Empty)
// Util.PrintCallStack();
string[] parts = dllName.Split(new char[] {':'});
dllName = parts[0];
string className = String.Empty;
if (parts.Length > 1)
className = parts[1];
// The path for a dynamic plugin will contain ":" on Windows
string[] parts = dllName.Split (new char[] {':'});
if (parts [0].Length > 1)
{
dllName = parts [0];
if (parts.Length > 1)
className = parts[1];
}
else
{
// This is Windows - we must replace the ":" in the path
dllName = String.Format ("{0}:{1}", parts [0], parts [1]);
if (parts.Length > 2)
className = parts[2];
}
return LoadPlugin<T>(dllName, className, args);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -32,9 +32,15 @@
<appender-ref ref="LogFileAppender" />
</root>
<!-- Independently control logging level for XEngine -->
<logger name="OpenSim.Region.ScriptEngine.XEngine">
<level value="INFO"/>
</logger>
<!-- Independently control logging level for per region module loading -->
<logger name="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin">
<level value="INFO"/>
</logger>
</log4net>
</configuration>

View File

@ -1364,6 +1364,10 @@
; If a script overruns it's event limit, kill the script?
KillTimedOutScripts = false
; Amount of time in milliseconds we will wait for an event to completely normally when a script stop is requested
; before aborting the thread (such as when an object containing scripts is taken into inventory).
WaitForEventCompletionOnScriptStop = 1000;
; Sets the multiplier for the scripting delays
ScriptDelayFactor = 1.0

View File

@ -22,6 +22,18 @@
; *
[Startup]
; Plugin Registry Location
; Set path to directory for plugin registry. Information
; about the registered repositories and installed plugins
; will be stored here
; The Robust.exe process must hvae R/W access to the location
RegistryLocation = "."
; Modular configurations
; Set path to directory for modular ini files...
; The Robust.exe process must hvae R/W access to the location
ConfigDirectory = "/home/opensim/etc/Configs"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
@ -53,19 +65,6 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
;; Additions for other add-on modules. For example:
;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector"
; Plugin Registry Location
; Set path to directory for plugin registry. Information
; about the registered repositories and installed plugins
; will be stored here
; The Robust.exe process must hvae R/W access to the location
RegistryLocation = "."
; Modular configurations
; Set path to directory for modular ini files...
; The Robust.exe process must hvae R/W access to the location
ConfigDirectory = "/home/opensim/etc/Configs"
; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above
; *

View File

@ -14,6 +14,19 @@
; *
[Startup]
; Plugin Registry Location
; Set path to directory for plugin registry. Information
; about the registered repositories and installed plugins
; will be stored here
; The Robust.exe process must hvae R/W access to the location
RegistryLocation = "."
; Modular configurations
; Set path to directory for modular ini files...
; The Robust.exe process must hvae R/W access to the location
ConfigDirectory = "/home/opensim/etc/Configs"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
@ -31,19 +44,6 @@ FriendsServiceConnector = "8003/OpenSim.Server.Handlers.dll:FriendsServiceConnec
MapAddServiceConnector = "8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
; Plugin Registry Location
; Set path to directory for plugin registry. Information
; about the registered repositories and installed plugins
; will be stored here
; The Robust.exe process must hvae R/W access to the location
RegistryLocation = "."
; Modular configurations
; Set path to directory for modular ini files...
; The Robust.exe process must hvae R/W access to the location
ConfigDirectory = "/home/opensim/etc/Configs"
; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above
; *