Merge branch 'master' into careminster

Conflicts:
	OpenSim/Data/MySQL/MySQLAssetData.cs
	OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
	OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
avinationmerge
Melanie 2013-04-10 13:20:55 +01:00
commit 7cf377fff0
34 changed files with 1621 additions and 1008 deletions

View File

@ -101,6 +101,7 @@ what it is today.
* jhurliman * jhurliman
* John R Sohn (XenReborn) * John R Sohn (XenReborn)
* jonc * jonc
* Jon Cundill
* Junta Kohime * Junta Kohime
* Kayne * Kayne
* Kevin Cozens * Kevin Cozens

View File

@ -142,7 +142,8 @@ namespace OpenSim.Data.MySQL
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error("[ASSETS DB]: MySql failure fetching asset " + assetID + ": " + e.Message); m_log.Error(
string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", assetID), e);
} }
} }
} }
@ -243,10 +244,11 @@ namespace OpenSim.Data.MySQL
} }
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat( m_log.Error(
"[ASSETS DB]: " + string.Format(
"MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() "[ASSETS DB]: Failure updating access_time for asset {0} with name {1}. Exception ",
+ Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); asset.FullID, asset.Name),
e);
} }
} }
} }
@ -286,8 +288,8 @@ namespace OpenSim.Data.MySQL
} }
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat( m_log.Error(
"[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", uuid), e);
} }
} }
} }
@ -346,7 +348,11 @@ namespace OpenSim.Data.MySQL
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); m_log.Error(
string.Format(
"[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ",
start, count),
e);
} }
} }
} }

View File

@ -76,6 +76,11 @@ namespace OpenSim.Framework.Servers
protected void CreatePIDFile(string path) protected void CreatePIDFile(string path)
{ {
if (File.Exists(path))
m_log.ErrorFormat(
"[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
path);
try try
{ {
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();

View File

@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
bool asAttachment) bool asAttachment)
{ {
CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
foreach (SceneObjectGroup objectGroup in objlist) foreach (SceneObjectGroup objectGroup in objlist)
{ {
@ -379,7 +379,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
objectGroup.AbsolutePosition.Z); objectGroup.AbsolutePosition.Z);
Quaternion inventoryStoredRotation = objectGroup.GroupRotation; Quaternion inventoryStoredRotation = objectGroup.GroupRotation;
originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; //originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
// Restore attachment data after trip through the sim // Restore attachment data after trip through the sim
if (objectGroup.RootPart.AttachPoint > 0) if (objectGroup.RootPart.AttachPoint > 0)
@ -418,9 +418,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
else else
itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
// Restore the position of each group now that it has been stored to inventory. // // Restore the position of each group now that it has been stored to inventory.
foreach (SceneObjectGroup objectGroup in objlist) // foreach (SceneObjectGroup objectGroup in objlist)
objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
@ -866,7 +866,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
return null; return null;
} }
if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
return null; return null;
for (int i = 0; i < objlist.Count; i++) for (int i = 0; i < objlist.Count; i++)
@ -965,10 +965,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
/// <param name="item"></param> /// <param name="item"></param>
/// <param name="objlist"></param> /// <param name="objlist"></param>
/// <param name="pos"></param> /// <param name="pos"></param>
/// <param name="veclist">
/// List of vector position adjustments for a coalesced objects. For ordinary objects
/// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
/// </param>
/// <param name="isAttachment"></param> /// <param name="isAttachment"></param>
/// <returns>true if we can processed with rezzing, false if we need to abort</returns> /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
private bool DoPreRezWhenFromItem( private bool DoPreRezWhenFromItem(
IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
Vector3 pos, List<Vector3> veclist, bool isAttachment)
{ {
UUID fromUserInventoryItemId = UUID.Zero; UUID fromUserInventoryItemId = UUID.Zero;
@ -991,28 +996,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
} }
} }
int primcount = 0; for (int i = 0; i < objlist.Count; i++)
foreach (SceneObjectGroup g in objlist)
primcount += g.PrimCount;
if (!m_Scene.Permissions.CanRezObject(
primcount, remoteClient.AgentId, pos)
&& !isAttachment)
{ {
// The client operates in no fail mode. It will SceneObjectGroup g = objlist[i];
// have already removed the item from the folder
// if it's no copy.
// Put it back if it's not an attachment
//
if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
remoteClient.SendBulkUpdateInventory(item);
ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); if (!m_Scene.Permissions.CanRezObject(
remoteClient.SendAlertMessage(string.Format( g.PrimCount, remoteClient.AgentId, pos + veclist[i])
"Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", && !isAttachment)
item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); {
// The client operates in no fail mode. It will
// have already removed the item from the folder
// if it's no copy.
// Put it back if it's not an attachment
//
if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
remoteClient.SendBulkUpdateInventory(item);
return false; ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
remoteClient.SendAlertMessage(string.Format(
"Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
return false;
}
} }
for (int i = 0; i < objlist.Count; i++) for (int i = 0; i < objlist.Count; i++)

View File

@ -412,7 +412,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
//public bool HttpVerboseThrottle = true; // not implemented //public bool HttpVerboseThrottle = true; // not implemented
public List<string> HttpCustomHeaders = null; public List<string> HttpCustomHeaders = null;
public bool HttpPragmaNoCache = true; public bool HttpPragmaNoCache = true;
private Thread httpThread;
// Request info // Request info
private UUID _itemID; private UUID _itemID;

View File

@ -1453,6 +1453,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
bool permission = false; bool permission = false;
// m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name);
ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
if (land == null) return false; if (land == null) return false;

View File

@ -5647,12 +5647,12 @@ Environment.Exit(1);
List<SceneObjectGroup> objects, List<SceneObjectGroup> objects,
out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
{ {
minX = 256; minX = float.MaxValue;
maxX = -256; maxX = float.MinValue;
minY = 256; minY = float.MaxValue;
maxY = -256; maxY = float.MinValue;
minZ = 8192; minZ = float.MaxValue;
maxZ = -256; maxZ = float.MinValue;
List<Vector3> offsets = new List<Vector3>(); List<Vector3> offsets = new List<Vector3>();

View File

@ -0,0 +1,285 @@
/*
* 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.Linq;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorAvatarMove : BSActor
{
BSVMotor m_velocityMotor;
public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj, actorName)
{
m_velocityMotor = null;
m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
}
// Release any connections and resources used by the actor.
// BSActor.Dispose()
public override void Dispose()
{
Enabled = false;
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
// If the object is physically active, add the hoverer prestep action
if (isActive)
{
ActivateAvatarMove();
}
else
{
DeactivateAvatarMove();
}
}
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
// Register a prestep action to restore physical requirements before the next simulation step.
// Called at taint-time.
// BSActor.RemoveBodyDependencies()
public override void RemoveBodyDependencies()
{
// Nothing to do for the hoverer since it is all software at pre-step action time.
}
// Usually called when target velocity changes to set the current velocity and the target
// into the movement motor.
public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
{
m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
{
if (m_velocityMotor != null)
{
m_velocityMotor.Reset();
m_velocityMotor.SetTarget(targ);
m_velocityMotor.SetCurrent(vel);
m_velocityMotor.Enabled = true;
}
});
}
// If a hover motor has not been created, create one and start the hovering.
private void ActivateAvatarMove()
{
if (m_velocityMotor == null)
{
// Infinite decay and timescale values so motor only changes current to target values.
m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
0.2f, // time scale
BSMotor.Infinite, // decay time scale
BSMotor.InfiniteVector, // friction timescale
1f // efficiency
);
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
m_physicsScene.BeforeStep += Mover;
}
}
private void DeactivateAvatarMove()
{
if (m_velocityMotor != null)
{
m_physicsScene.BeforeStep -= Mover;
m_velocityMotor = null;
}
}
// Called just before the simulation step. Update the vertical position for hoverness.
private void Mover(float timeStep)
{
// Don't do movement while the object is selected.
if (!isActive)
return;
// TODO: Decide if the step parameters should be changed depending on the avatar's
// state (flying, colliding, ...). There is code in ODE to do this.
// COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
// specified for the avatar is the one that should be used. For falling, if the avatar
// is not flying and is not colliding then it is presumed to be falling and the Z
// component is not fooled with (thus allowing gravity to do its thing).
// When the avatar is standing, though, the user has specified a velocity of zero and
// the avatar should be standing. But if the avatar is pushed by something in the world
// (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
// move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
// errors can creap in and the avatar will slowly float off in some direction.
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
// from real pushing.
// The code below uses whether the collider is static or moving to decide whether to zero motion.
m_velocityMotor.Step(timeStep);
m_controllingPrim.IsStationary = false;
// If we're not supposed to be moving, make sure things are zero.
if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
{
// The avatar shouldn't be moving
m_velocityMotor.Zero();
if (m_controllingPrim.IsColliding)
{
// If we are colliding with a stationary object, presume we're standing and don't move around
if (!m_controllingPrim.ColliderIsMoving)
{
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
m_controllingPrim.IsStationary = true;
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
}
// Standing has more friction on the ground
if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
{
m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
}
}
else
{
if (m_controllingPrim.Flying)
{
// Flying and not collising and velocity nearly zero.
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
}
}
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
}
else
{
// Supposed to be moving.
OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
if (m_controllingPrim.Friction != BSParam.AvatarFriction)
{
// Probably starting up walking. Set friction to moving friction.
m_controllingPrim.Friction = BSParam.AvatarFriction;
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
}
// If falling, we keep the world's downward vector no matter what the other axis specify.
// The check for RawVelocity.Z < 0 makes jumping work (temporary upward force).
if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
{
if (m_controllingPrim.RawVelocity.Z < 0)
stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
}
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
// Should we check for move force being small and forcing velocity to zero?
// Add special movement force to allow avatars to walk up stepped surfaces.
moveForce += WalkUpStairs();
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
}
}
// Decide if the character is colliding with a low object and compute a force to pop the
// avatar up so it can walk up and over the low objects.
private OMV.Vector3 WalkUpStairs()
{
OMV.Vector3 ret = OMV.Vector3.Zero;
// This test is done if moving forward, not flying and is colliding with something.
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
{
// The range near the character's feet where we will consider stairs
float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
// Look for a collision point that is near the character's feet and is oriented the same as the charactor is
foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
{
// Don't care about collisions with the terrain
if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
{
OMV.Vector3 touchPosition = kvp.Value.Position;
// DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
// LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
{
// This contact is within the 'near the feet' range.
// The normal should be our contact point to the object so it is pointing away
// thus the difference between our facing orientation and the normal should be small.
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
if (diff < BSParam.AvatarStepApproachFactor)
{
// Found the stairs contact point. Push up a little to raise the character.
float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
ret = new OMV.Vector3(0f, 0f, upForce);
// Also move the avatar up for the new height
OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
}
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
}
}
}
}
return ret;
}
}
}

View File

@ -0,0 +1,174 @@
/*
* 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.Linq;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorHover : BSActor
{
private BSFMotor m_hoverMotor;
public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj, actorName)
{
m_hoverMotor = null;
m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled; }
}
// Release any connections and resources used by the actor.
// BSActor.Dispose()
public override void Dispose()
{
Enabled = false;
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
// If not active any more, turn me off
if (!m_controllingPrim.HoverActive)
{
SetEnabled(false);
}
// If the object is physically active, add the hoverer prestep action
if (isActive)
{
ActivateHover();
}
else
{
DeactivateHover();
}
}
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
// Register a prestep action to restore physical requirements before the next simulation step.
// Called at taint-time.
// BSActor.RemoveBodyDependencies()
public override void RemoveBodyDependencies()
{
// Nothing to do for the hoverer since it is all software at pre-step action time.
}
// If a hover motor has not been created, create one and start the hovering.
private void ActivateHover()
{
if (m_hoverMotor == null)
{
// Turning the target on
m_hoverMotor = new BSFMotor("BSActorHover",
m_controllingPrim.HoverTau, // timeScale
BSMotor.Infinite, // decay time scale
BSMotor.Infinite, // friction timescale
1f // efficiency
);
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
m_physicsScene.BeforeStep += Hoverer;
}
}
private void DeactivateHover()
{
if (m_hoverMotor != null)
{
m_physicsScene.BeforeStep -= Hoverer;
m_hoverMotor = null;
}
}
// Called just before the simulation step. Update the vertical position for hoverness.
private void Hoverer(float timeStep)
{
// Don't do hovering while the object is selected.
if (!isActive)
return;
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
float targetHeight = m_hoverMotor.Step(timeStep);
// 'targetHeight' is where we'd like the Z of the prim to be at this moment.
// Compute the amount of force to push us there.
float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
// Undo anything the object thinks it's doing at the moment
moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
}
// Based on current position, determine what we should be hovering at now.
// Must recompute often. What if we walked offa cliff>
private float ComputeCurrentHoverHeight()
{
float ret = m_controllingPrim.HoverHeight;
float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
switch (m_controllingPrim.HoverType)
{
case PIDHoverType.Ground:
ret = groundHeight + m_controllingPrim.HoverHeight;
break;
case PIDHoverType.GroundAndWater:
float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
if (groundHeight > waterHeight)
{
ret = groundHeight + m_controllingPrim.HoverHeight;
}
else
{
ret = waterHeight + m_controllingPrim.HoverHeight;
}
break;
}
return ret;
}
}
}

View File

@ -36,11 +36,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSActorLockAxis : BSActor public class BSActorLockAxis : BSActor
{ {
bool TryExperimentalLockAxisCode = true;
BSConstraint LockAxisConstraint = null; BSConstraint LockAxisConstraint = null;
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj,actorName) : base(physicsScene, pObj, actorName)
{ {
m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
LockAxisConstraint = null; LockAxisConstraint = null;
@ -69,18 +68,13 @@ public class BSActorLockAxis : BSActor
// If all the axis are free, we don't need to exist // If all the axis are free, we don't need to exist
if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree)
{ {
m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,allAxisFree,removing={1}", m_controllingPrim.LocalID, ActorName); Enabled = false;
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
return;
} }
// If the object is physically active, add the axis locking constraint // If the object is physically active, add the axis locking constraint
if (Enabled if (isActive)
&& m_controllingPrim.IsPhysicallyActive
&& TryExperimentalLockAxisCode
&& m_controllingPrim.LockedAxis != m_controllingPrim.LockedAxisFree)
{ {
if (LockAxisConstraint == null) AddAxisLockConstraint();
AddAxisLockConstraint();
} }
else else
{ {
@ -99,7 +93,7 @@ public class BSActorLockAxis : BSActor
// If a constraint is set up, remove it from the physical scene // If a constraint is set up, remove it from the physical scene
RemoveAxisLockConstraint(); RemoveAxisLockConstraint();
// Schedule a call before the next simulation step to restore the constraint. // Schedule a call before the next simulation step to restore the constraint.
m_physicsScene.PostTaintObject(m_controllingPrim.LockedAxisActorName, m_controllingPrim.LocalID, delegate() m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate()
{ {
Refresh(); Refresh();
}); });
@ -108,58 +102,61 @@ public class BSActorLockAxis : BSActor
private void AddAxisLockConstraint() private void AddAxisLockConstraint()
{ {
// Lock that axis by creating a 6DOF constraint that has one end in the world and if (LockAxisConstraint == null)
// the other in the object.
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
// Remove any existing axis constraint (just to be sure)
RemoveAxisLockConstraint();
BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
OMV.Vector3.Zero, OMV.Quaternion.Identity,
false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
// The constraint is tied to the world and oriented to the prim.
// Free to move linearly in the region
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float fPI = (float)Math.PI;
OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
if (m_controllingPrim.LockedAxis.X != 1f)
{ {
angularLow.X = 0f; // Lock that axis by creating a 6DOF constraint that has one end in the world and
angularHigh.X = 0f; // the other in the object.
} // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
if (m_controllingPrim.LockedAxis.Y != 1f) // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (m_controllingPrim.LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
{
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
}
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", // Remove any existing axis constraint (just to be sure)
m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); RemoveAxisLockConstraint();
// Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); OMV.Vector3.Zero, OMV.Quaternion.Identity,
false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); // The constraint is tied to the world and oriented to the prim.
// Free to move linearly in the region
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float fPI = (float)Math.PI;
OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
if (m_controllingPrim.LockedAxis.X != 1f)
{
angularLow.X = 0f;
angularHigh.X = 0f;
}
if (m_controllingPrim.LockedAxis.Y != 1f)
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (m_controllingPrim.LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
{
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
}
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);
// Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
}
} }
private void RemoveAxisLockConstraint() private void RemoveAxisLockConstraint()

View File

@ -0,0 +1,158 @@
/*
* 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.Linq;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorMoveToTarget : BSActor
{
private BSVMotor m_targetMotor;
public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj, actorName)
{
m_targetMotor = null;
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled; }
}
// Release any connections and resources used by the actor.
// BSActor.Dispose()
public override void Dispose()
{
Enabled = false;
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
// If not active any more...
if (!m_controllingPrim.MoveToTargetActive)
{
Enabled = false;
}
if (isActive)
{
ActivateMoveToTarget();
}
else
{
DeactivateMoveToTarget();
}
}
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
// Register a prestep action to restore physical requirements before the next simulation step.
// Called at taint-time.
// BSActor.RemoveBodyDependencies()
public override void RemoveBodyDependencies()
{
// Nothing to do for the moveToTarget since it is all software at pre-step action time.
}
// If a hover motor has not been created, create one and start the hovering.
private void ActivateMoveToTarget()
{
if (m_targetMotor == null)
{
// We're taking over after this.
m_controllingPrim.ZeroMotion(true);
m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate",
m_controllingPrim.MoveToTargetTau, // timeScale
BSMotor.Infinite, // decay time scale
BSMotor.InfiniteVector, // friction timescale
1f // efficiency
);
m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
m_physicsScene.BeforeStep += Mover;
}
}
private void DeactivateMoveToTarget()
{
if (m_targetMotor != null)
{
m_physicsScene.BeforeStep -= Mover;
m_targetMotor = null;
}
}
// Called just before the simulation step. Update the vertical position for hoverness.
private void Mover(float timeStep)
{
// Don't do hovering while the object is selected.
if (!isActive)
return;
OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
// 'movePosition' is where we'd like the prim to be at this moment.
OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
// If we are very close to our target, turn off the movement motor.
if (m_targetMotor.ErrorIsZero())
{
m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
// Setting the position does not cause the physics engine to generate a property update. Force it.
m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
}
else
{
m_controllingPrim.ForcePosition = movePosition;
// Setting the position does not cause the physics engine to generate a property update. Force it.
m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
}
m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition);
}
}
}

View File

@ -0,0 +1,137 @@
/*
* 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.Linq;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorSetForce : BSActor
{
BSFMotor m_forceMotor;
public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj, actorName)
{
m_forceMotor = null;
m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
}
// Release any connections and resources used by the actor.
// BSActor.Dispose()
public override void Dispose()
{
Enabled = false;
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
{
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
Enabled = false;
return;
}
// If the object is physically active, add the hoverer prestep action
if (isActive)
{
ActivateSetForce();
}
else
{
DeactivateSetForce();
}
}
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
// Register a prestep action to restore physical requirements before the next simulation step.
// Called at taint-time.
// BSActor.RemoveBodyDependencies()
public override void RemoveBodyDependencies()
{
// Nothing to do for the hoverer since it is all software at pre-step action time.
}
// If a hover motor has not been created, create one and start the hovering.
private void ActivateSetForce()
{
if (m_forceMotor == null)
{
// A fake motor that might be used someday
m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f, 1f);
m_physicsScene.BeforeStep += Mover;
}
}
private void DeactivateSetForce()
{
if (m_forceMotor != null)
{
m_physicsScene.BeforeStep -= Mover;
m_forceMotor = null;
}
}
// Called just before the simulation step. Update the vertical position for hoverness.
private void Mover(float timeStep)
{
// Don't do force while the object is selected.
if (!isActive)
return;
m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
if (m_controllingPrim.PhysBody.HasPhysicalBody)
{
m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
m_controllingPrim.ActivateIfPhysical(false);
}
// TODO:
}
}
}

View File

@ -0,0 +1,138 @@
/*
* 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.Linq;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorSetTorque : BSActor
{
BSFMotor m_torqueMotor;
public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj, actorName)
{
m_torqueMotor = null;
m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
}
// Release any connections and resources used by the actor.
// BSActor.Dispose()
public override void Dispose()
{
Enabled = false;
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
{
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
Enabled = false;
return;
}
// If the object is physically active, add the hoverer prestep action
if (isActive)
{
ActivateSetTorque();
}
else
{
DeactivateSetTorque();
}
}
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
// Register a prestep action to restore physical requirements before the next simulation step.
// Called at taint-time.
// BSActor.RemoveBodyDependencies()
public override void RemoveBodyDependencies()
{
// Nothing to do for the hoverer since it is all software at pre-step action time.
}
// If a hover motor has not been created, create one and start the hovering.
private void ActivateSetTorque()
{
if (m_torqueMotor == null)
{
// A fake motor that might be used someday
m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f, 1f);
m_physicsScene.BeforeStep += Mover;
}
}
private void DeactivateSetTorque()
{
if (m_torqueMotor != null)
{
m_physicsScene.BeforeStep -= Mover;
m_torqueMotor = null;
}
}
// Called just before the simulation step. Update the vertical position for hoverness.
private void Mover(float timeStep)
{
// Don't do force while the object is selected.
if (!isActive)
return;
m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
if (m_controllingPrim.PhysBody.HasPhysicalBody)
{
m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
m_controllingPrim.ActivateIfPhysical(false);
}
// TODO:
}
}
}

View File

@ -32,45 +32,72 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSActorCollection public class BSActorCollection
{ {
private BSScene PhysicsScene { get; set; } private BSScene m_physicsScene { get; set; }
private Dictionary<string, BSActor> m_actors; private Dictionary<string, BSActor> m_actors;
public BSActorCollection(BSScene physicsScene) public BSActorCollection(BSScene physicsScene)
{ {
PhysicsScene = physicsScene; m_physicsScene = physicsScene;
m_actors = new Dictionary<string, BSActor>(); m_actors = new Dictionary<string, BSActor>();
} }
public void Add(string name, BSActor actor) public void Add(string name, BSActor actor)
{ {
m_actors[name] = actor; lock (m_actors)
{
if (!m_actors.ContainsKey(name))
{
m_actors[name] = actor;
}
}
} }
public bool RemoveAndRelease(string name) public bool RemoveAndRelease(string name)
{ {
bool ret = false; bool ret = false;
if (m_actors.ContainsKey(name)) lock (m_actors)
{ {
BSActor beingRemoved = m_actors[name]; if (m_actors.ContainsKey(name))
beingRemoved.Dispose(); {
m_actors.Remove(name); BSActor beingRemoved = m_actors[name];
ret = true; m_actors.Remove(name);
beingRemoved.Dispose();
ret = true;
}
} }
return ret; return ret;
} }
public void Clear() public void Clear()
{ {
Release(); lock (m_actors)
m_actors.Clear(); {
Release();
m_actors.Clear();
}
}
public void Dispose()
{
Clear();
} }
public bool HasActor(string name) public bool HasActor(string name)
{ {
return m_actors.ContainsKey(name); return m_actors.ContainsKey(name);
} }
public bool TryGetActor(string actorName, out BSActor theActor)
{
return m_actors.TryGetValue(actorName, out theActor);
}
public void ForEachActor(Action<BSActor> act) public void ForEachActor(Action<BSActor> act)
{ {
foreach (KeyValuePair<string, BSActor> kvp in m_actors) lock (m_actors)
act(kvp.Value); {
foreach (KeyValuePair<string, BSActor> kvp in m_actors)
act(kvp.Value);
}
} }
public void Enable(bool enabl)
{
ForEachActor(a => a.SetEnabled(enabl));
}
public void Release() public void Release()
{ {
ForEachActor(a => a.Dispose()); ForEachActor(a => a.Dispose());
@ -98,7 +125,7 @@ public abstract class BSActor
{ {
protected BSScene m_physicsScene { get; private set; } protected BSScene m_physicsScene { get; private set; }
protected BSPhysObject m_controllingPrim { get; private set; } protected BSPhysObject m_controllingPrim { get; private set; }
protected bool Enabled { get; set; } public virtual bool Enabled { get; set; }
public string ActorName { get; private set; } public string ActorName { get; private set; }
public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
@ -114,8 +141,10 @@ public abstract class BSActor
{ {
get { return Enabled; } get { return Enabled; }
} }
// Turn the actor on an off.
public virtual void Enable(bool setEnabled) // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
// Anyone else should assign true/false to 'Enabled'.
public void SetEnabled(bool setEnabled)
{ {
Enabled = setEnabled; Enabled = setEnabled;
} }

View File

@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject
private OMV.Vector3 _position; private OMV.Vector3 _position;
private float _mass; private float _mass;
private float _avatarVolume; private float _avatarVolume;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
private OMV.Vector3 _torque;
private float _collisionScore; private float _collisionScore;
private OMV.Vector3 _acceleration; private OMV.Vector3 _acceleration;
private OMV.Quaternion _orientation; private OMV.Quaternion _orientation;
@ -61,17 +58,13 @@ public sealed class BSCharacter : BSPhysObject
private OMV.Vector3 _rotationalVelocity; private OMV.Vector3 _rotationalVelocity;
private bool _kinematic; private bool _kinematic;
private float _buoyancy; private float _buoyancy;
private bool _isStationaryStanding; // true is standing on a stationary object
private BSVMotor _velocityMotor; private BSActorAvatarMove m_moveActor;
private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
private OMV.Vector3 _PIDTarget; private OMV.Vector3 _PIDTarget;
private bool _usePID; private bool _usePID;
private float _PIDTau; private float _PIDTau;
private bool _useHoverPID;
private float _PIDHoverHeight;
private PIDHoverType _PIDHoverType;
private float _PIDHoverTao;
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
: base(parent_scene, localID, avName, "BSCharacter") : base(parent_scene, localID, avName, "BSCharacter")
@ -81,11 +74,10 @@ public sealed class BSCharacter : BSPhysObject
_flying = isFlying; _flying = isFlying;
_orientation = OMV.Quaternion.Identity; _orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
Friction = BSParam.AvatarStandingFriction; Friction = BSParam.AvatarStandingFriction;
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
_isStationaryStanding = false;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero, // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values. // replace with the default values.
@ -99,7 +91,12 @@ public sealed class BSCharacter : BSPhysObject
// set _avatarVolume and _mass based on capsule size, _density and Scale // set _avatarVolume and _mass based on capsule size, _density and Scale
ComputeAvatarVolumeAndMass(); ComputeAvatarVolumeAndMass();
SetupMovementMotor(); // The avatar's movement is controlled by this motor that speeds up and slows down
// the avatar seeking to reach the motor's target speed.
// This motor runs as a prestep action for the avatar so it will keep the avatar
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName);
PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, Density, _avatarVolume, RawMass); LocalID, _size, Scale, Density, _avatarVolume, RawMass);
@ -139,10 +136,10 @@ public sealed class BSCharacter : BSPhysObject
ForcePosition = _position; ForcePosition = _position;
// Set the velocity // Set the velocity
_velocityMotor.Reset(); if (m_moveActor != null)
_velocityMotor.SetTarget(_velocity); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
_velocityMotor.SetCurrent(_velocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
// This will enable or disable the flying buoyancy of the avatar. // This will enable or disable the flying buoyancy of the avatar.
// Needs to be reset especially when an avatar is recreated after crossing a region boundry. // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
@ -163,6 +160,9 @@ public sealed class BSCharacter : BSPhysObject
// Make so capsule does not fall over // Make so capsule does not fall over
PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
// The avatar mover sets some parameters.
PhysicalActors.Refresh();
PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
@ -176,162 +176,6 @@ public sealed class BSCharacter : BSPhysObject
PhysBody.ApplyCollisionMask(PhysicsScene); PhysBody.ApplyCollisionMask(PhysicsScene);
} }
// The avatar's movement is controlled by this motor that speeds up and slows down
// the avatar seeking to reach the motor's target speed.
// This motor runs as a prestep action for the avatar so it will keep the avatar
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
private void SetupMovementMotor()
{
// Infinite decay and timescale values so motor only changes current to target values.
_velocityMotor = new BSVMotor("BSCharacter.Velocity",
0.2f, // time scale
BSMotor.Infinite, // decay time scale
BSMotor.InfiniteVector, // friction timescale
1f // efficiency
);
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
{
// TODO: Decide if the step parameters should be changed depending on the avatar's
// state (flying, colliding, ...). There is code in ODE to do this.
// COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
// specified for the avatar is the one that should be used. For falling, if the avatar
// is not flying and is not colliding then it is presumed to be falling and the Z
// component is not fooled with (thus allowing gravity to do its thing).
// When the avatar is standing, though, the user has specified a velocity of zero and
// the avatar should be standing. But if the avatar is pushed by something in the world
// (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
// move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
// errors can creap in and the avatar will slowly float off in some direction.
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
// from real pushing.
// The code below uses whether the collider is static or moving to decide whether to zero motion.
_velocityMotor.Step(timeStep);
_isStationaryStanding = false;
// If we're not supposed to be moving, make sure things are zero.
if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
{
// The avatar shouldn't be moving
_velocityMotor.Zero();
if (IsColliding)
{
// If we are colliding with a stationary object, presume we're standing and don't move around
if (!ColliderIsMoving)
{
DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
_isStationaryStanding = true;
ZeroMotion(true /* inTaintTime */);
}
// Standing has more friction on the ground
if (Friction != BSParam.AvatarStandingFriction)
{
Friction = BSParam.AvatarStandingFriction;
PhysicsScene.PE.SetFriction(PhysBody, Friction);
}
}
else
{
if (Flying)
{
// Flying and not collising and velocity nearly zero.
ZeroMotion(true /* inTaintTime */);
}
}
DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
}
else
{
// Supposed to be moving.
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
if (Friction != BSParam.AvatarFriction)
{
// Probably starting up walking. Set friction to moving friction.
Friction = BSParam.AvatarFriction;
PhysicsScene.PE.SetFriction(PhysBody, Friction);
}
// If falling, we keep the world's downward vector no matter what the other axis specify.
// The check for _velocity.Z < 0 makes jumping work (temporary upward force).
if (!Flying && !IsColliding)
{
if (_velocity.Z < 0)
stepVelocity.Z = _velocity.Z;
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
}
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
// Should we check for move force being small and forcing velocity to zero?
// Add special movement force to allow avatars to walk up stepped surfaces.
moveForce += WalkUpStairs();
DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
}
});
}
// Decide if the character is colliding with a low object and compute a force to pop the
// avatar up so it can walk up and over the low objects.
private OMV.Vector3 WalkUpStairs()
{
OMV.Vector3 ret = OMV.Vector3.Zero;
// This test is done if moving forward, not flying and is colliding with something.
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
{
// The range near the character's feet where we will consider stairs
float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
// Look for a collision point that is near the character's feet and is oriented the same as the charactor is
foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
{
// Don't care about collisions with the terrain
if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
{
OMV.Vector3 touchPosition = kvp.Value.Position;
// DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
// LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
{
// This contact is within the 'near the feet' range.
// The normal should be our contact point to the object so it is pointing away
// thus the difference between our facing orientation and the normal should be small.
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
if (diff < BSParam.AvatarStepApproachFactor)
{
// Found the stairs contact point. Push up a little to raise the character.
float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
ret = new OMV.Vector3(0f, 0f, upForce);
// Also move the avatar up for the new height
OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
ForcePosition = RawPosition + displacement;
}
DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
}
}
}
}
return ret;
}
public override void RequestPhysicsterseUpdate() public override void RequestPhysicsterseUpdate()
{ {
@ -403,7 +247,7 @@ public sealed class BSCharacter : BSPhysObject
// Called at taint time! // Called at taint time!
public override void ZeroMotion(bool inTaintTime) public override void ZeroMotion(bool inTaintTime)
{ {
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
@ -542,15 +386,15 @@ public sealed class BSCharacter : BSPhysObject
} }
public override OMV.Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return RawForce; }
set { set {
_force = value; RawForce = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
{ {
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
PhysicsScene.PE.SetObjectForce(PhysBody, _force); PhysicsScene.PE.SetObjectForce(PhysBody, RawForce);
}); });
} }
} }
@ -573,7 +417,7 @@ public sealed class BSCharacter : BSPhysObject
{ {
get get
{ {
return m_targetVelocity; return base.m_targetVelocity;
} }
set set
{ {
@ -583,51 +427,39 @@ public sealed class BSCharacter : BSPhysObject
if (_setAlwaysRun) if (_setAlwaysRun)
targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() if (m_moveActor != null)
{ m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
_velocityMotor.Reset();
_velocityMotor.SetTarget(targetVel);
_velocityMotor.SetCurrent(_velocity);
_velocityMotor.Enabled = true;
});
} }
} }
public override OMV.Vector3 RawVelocity
{
get { return _velocity; }
set { _velocity = value; }
}
// Directly setting velocity means this is what the user really wants now. // Directly setting velocity means this is what the user really wants now.
public override OMV.Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
_velocity = value; RawVelocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
{ {
_velocityMotor.Reset(); if (m_moveActor != null)
_velocityMotor.SetCurrent(_velocity); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
_velocityMotor.SetTarget(_velocity);
_velocityMotor.Enabled = false;
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
}); });
} }
} }
public override OMV.Vector3 ForceVelocity { public override OMV.Vector3 ForceVelocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
_velocity = value; RawVelocity = value;
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
PhysicsScene.PE.Activate(PhysBody, true); PhysicsScene.PE.Activate(PhysBody, true);
} }
} }
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return RawTorque; }
set { _torque = value; set { RawTorque = value;
} }
} }
public override float CollisionScore { public override float CollisionScore {
@ -783,27 +615,6 @@ public sealed class BSCharacter : BSPhysObject
set { _PIDTau = value; } set { _PIDTau = value; }
} }
// Used for llSetHoverHeight and maybe vehicle height
// Hover Height will override MoveTo target's Z
public override bool PIDHoverActive {
set { _useHoverPID = value; }
}
public override float PIDHoverHeight {
set { _PIDHoverHeight = value; }
}
public override PIDHoverType PIDHoverType {
set { _PIDHoverType = value; }
}
public override float PIDHoverTau {
set { _PIDHoverTao = value; }
}
// For RotLookAt
public override OMV.Quaternion APIDTarget { set { return; } }
public override bool APIDActive { set { return; } }
public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } }
public override void AddForce(OMV.Vector3 force, bool pushforce) public override void AddForce(OMV.Vector3 force, bool pushforce)
{ {
// Since this force is being applied in only one step, make this a force per second. // Since this force is being applied in only one step, make this a force per second.
@ -833,7 +644,7 @@ public sealed class BSCharacter : BSPhysObject
} }
} }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
} }
public override void SetMomentum(OMV.Vector3 momentum) { public override void SetMomentum(OMV.Vector3 momentum) {
} }
@ -887,7 +698,7 @@ public sealed class BSCharacter : BSPhysObject
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
// Don't change position if standing on a stationary object. // Don't change position if standing on a stationary object.
if (!_isStationaryStanding) if (!IsStationary)
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
@ -896,8 +707,8 @@ public sealed class BSCharacter : BSPhysObject
// and will send agent updates to the clients if velocity changes by more than // and will send agent updates to the clients if velocity changes by more than
// 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
// extra updates. // extra updates.
if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
_velocity = entprop.Velocity; RawVelocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
@ -920,7 +731,7 @@ public sealed class BSCharacter : BSPhysObject
// base.RequestPhysicsterseUpdate(); // base.RequestPhysicsterseUpdate();
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity);
} }
} }
} }

View File

@ -1358,6 +1358,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// If vertical attaction timescale is reasonable // If vertical attaction timescale is reasonable
if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
{ {
//Another formula to try got from :
//http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation;
// Flipping what was originally a timescale into a speed variable and then multiplying it by 2
// since only computing half the distance between the angles.
float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
// Make a prediction of where the up axis will be when this is applied rather then where it is now as
// this makes for a smoother adjustment and less fighting between the various forces.
Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
// This is only half the distance to the target so it will take 2 seconds to complete the turn.
Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
// Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed;
VehicleRotationalVelocity += vertContributionV;
VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}",
ControllingPrim.LocalID,
VehicleUpAxis,
predictedUp,
torqueVector,
vertContributionV);
//=====================================================================
/*
// Possible solution derived from a discussion at: // Possible solution derived from a discussion at:
// http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
@ -1392,6 +1421,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
differenceAngle, differenceAngle,
correctionRotation, correctionRotation,
vertContributionV); vertContributionV);
*/
// =================================================================== // ===================================================================
/* /*

View File

@ -86,6 +86,7 @@ public static class BSParam
public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
public static bool ShouldRemoveZeroWidthTriangles { get; private set; } public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
public static bool ShouldUseBulletHACD { get; set; }
public static float TerrainImplementation { get; private set; } public static float TerrainImplementation { get; private set; }
public static int TerrainMeshMagnification { get; private set; } public static int TerrainMeshMagnification { get; private set; }
@ -149,6 +150,15 @@ public static class BSParam
public static float CSHullVolumeConservationThresholdPercent { get; private set; } public static float CSHullVolumeConservationThresholdPercent { get; private set; }
public static int CSHullMaxVertices { get; private set; } public static int CSHullMaxVertices { get; private set; }
public static float CSHullMaxSkinWidth { get; private set; } public static float CSHullMaxSkinWidth { get; private set; }
public static float BHullMaxVerticesPerHull { get; private set; } // 100
public static float BHullMinClusters { get; private set; } // 2
public static float BHullCompacityWeight { get; private set; } // 0.1
public static float BHullVolumeWeight { get; private set; } // 0.0
public static float BHullConcavity { get; private set; } // 100
public static bool BHullAddExtraDistPoints { get; private set; } // false
public static bool BHullAddNeighboursDistPoints { get; private set; } // false
public static bool BHullAddFacesPoints { get; private set; } // false
public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
// Linkset implementation parameters // Linkset implementation parameters
public static float LinksetImplementation { get; private set; } public static float LinksetImplementation { get; private set; }
@ -325,6 +335,10 @@ public static class BSParam
true, true,
(s) => { return ShouldRemoveZeroWidthTriangles; }, (s) => { return ShouldRemoveZeroWidthTriangles; },
(s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ),
new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
false,
(s) => { return ShouldUseBulletHACD; },
(s,v) => { ShouldUseBulletHACD = v; } ),
new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
5, 5,
@ -663,10 +677,47 @@ public static class BSParam
(s) => { return CSHullMaxVertices; }, (s) => { return CSHullMaxVertices; },
(s,v) => { CSHullMaxVertices = v; } ), (s,v) => { CSHullMaxVertices = v; } ),
new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
0, 0f,
(s) => { return CSHullMaxSkinWidth; }, (s) => { return CSHullMaxSkinWidth; },
(s,v) => { CSHullMaxSkinWidth = v; } ), (s,v) => { CSHullMaxSkinWidth = v; } ),
new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
100f,
(s) => { return BHullMaxVerticesPerHull; },
(s,v) => { BHullMaxVerticesPerHull = v; } ),
new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
2f,
(s) => { return BHullMinClusters; },
(s,v) => { BHullMinClusters = v; } ),
new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
2f,
(s) => { return BHullCompacityWeight; },
(s,v) => { BHullCompacityWeight = v; } ),
new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
0.1f,
(s) => { return BHullVolumeWeight; },
(s,v) => { BHullVolumeWeight = v; } ),
new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
100f,
(s) => { return BHullConcavity; },
(s,v) => { BHullConcavity = v; } ),
new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
false,
(s) => { return BHullAddExtraDistPoints; },
(s,v) => { BHullAddExtraDistPoints = v; } ),
new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
false,
(s) => { return BHullAddNeighboursDistPoints; },
(s,v) => { BHullAddNeighboursDistPoints = v; } ),
new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
false,
(s) => { return BHullAddFacesPoints; },
(s,v) => { BHullAddFacesPoints = v; } ),
new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
false,
(s) => { return BHullShouldAdjustCollisionMargin; },
(s,v) => { BHullShouldAdjustCollisionMargin = v; } ),
new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound, (float)BSLinkset.LinksetImplementation.Compound,
(s) => { return LinksetImplementation; }, (s) => { return LinksetImplementation; },

View File

@ -43,7 +43,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
* VariableName: used by the simulator and performs taint operations, etc * VariableName: used by the simulator and performs taint operations, etc
* RawVariableName: direct reference to the BulletSim storage for the variable value * RawVariableName: direct reference to the BulletSim storage for the variable value
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine. * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
* The last two (and certainly the last one) should be referenced only in taint-time. * The last one should only be referenced in taint-time.
*/ */
/* /*
@ -84,6 +84,7 @@ public abstract class BSPhysObject : PhysicsActor
// Initialize variables kept in base. // Initialize variables kept in base.
GravModifier = 1.0f; GravModifier = 1.0f;
Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
HoverActive = false;
// We don't have any physical representation yet. // We don't have any physical representation yet.
PhysBody = new BulletBody(localID); PhysBody = new BulletBody(localID);
@ -110,11 +111,10 @@ public abstract class BSPhysObject : PhysicsActor
// Tell the object to clean up. // Tell the object to clean up.
public virtual void Destroy() public virtual void Destroy()
{ {
UnRegisterAllPreStepActions(); PhysicalActors.Enable(false);
UnRegisterAllPostStepActions();
PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate()
{ {
PhysicalActors.Release(); PhysicalActors.Dispose();
}); });
} }
@ -203,15 +203,48 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Quaternion RawOrientation { get; set; } public abstract OMV.Quaternion RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { get; set; } public abstract OMV.Quaternion ForceOrientation { get; set; }
public abstract OMV.Vector3 RawVelocity { get; set; } public OMV.Vector3 RawVelocity { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; } public abstract OMV.Vector3 ForceVelocity { get; set; }
public OMV.Vector3 RawForce { get; set; }
public OMV.Vector3 RawTorque { get; set; }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
{
AddAngularForce(force, pushforce, false);
}
public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
public abstract float ForceBuoyancy { get; set; } public abstract float ForceBuoyancy { get; set; }
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
public override bool PIDActive { set { MoveToTargetActive = value; } }
public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
public override float PIDTau { set { MoveToTargetTau = value; } }
public bool MoveToTargetActive { get; set; }
public OMV.Vector3 MoveToTargetTarget { get; set; }
public float MoveToTargetTau { get; set; }
// Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
public override bool PIDHoverActive { set { HoverActive = value; } }
public override float PIDHoverHeight { set { HoverHeight = value; } }
public override PIDHoverType PIDHoverType { set { HoverType = value; } }
public override float PIDHoverTau { set { HoverTau = value; } }
public bool HoverActive { get; set; }
public float HoverHeight { get; set; }
public PIDHoverType HoverType { get; set; }
public float HoverTau { get; set; }
// For RotLookAt
public override OMV.Quaternion APIDTarget { set { return; } }
public override bool APIDActive { set { return; } }
public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } }
// The current velocity forward // The current velocity forward
public virtual float ForwardSpeed public virtual float ForwardSpeed
{ {
@ -237,7 +270,51 @@ public abstract class BSPhysObject : PhysicsActor
public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
public readonly String LockedAxisActorName = "BSPrim.LockedAxis";
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
// they need waking up when parameters are changed.
// Called in taint-time!!
public void ActivateIfPhysical(bool forceIt)
{
if (IsPhysical && PhysBody.HasPhysicalBody)
PhysicsScene.PE.Activate(PhysBody, forceIt);
}
// 'actors' act on the physical object to change or constrain its motion. These can range from
// hovering to complex vehicle motion.
// May be called at non-taint time as this just adds the actor to the action list and the real
// work is done during the simulation step.
// Note that, if the actor is already in the list and we are disabling same, the actor is just left
// in the list disabled.
public delegate BSActor CreateActor();
public void EnableActor(bool enableActor, string actorName, CreateActor creator)
{
lock (PhysicalActors)
{
BSActor theActor;
if (PhysicalActors.TryGetActor(actorName, out theActor))
{
// The actor already exists so just turn it on or off
DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
theActor.Enabled = enableActor;
}
else
{
// The actor does not exist. If it should, create it.
if (enableActor)
{
DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
theActor = creator();
PhysicalActors.Add(actorName, theActor);
theActor.Enabled = true;
}
else
{
DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
}
}
}
}
#region Collisions #region Collisions
@ -255,7 +332,9 @@ public abstract class BSPhysObject : PhysicsActor
protected CollisionFlags CurrentCollisionFlags { get; set; } protected CollisionFlags CurrentCollisionFlags { get; set; }
// On a collision, check the collider and remember if the last collider was moving // On a collision, check the collider and remember if the last collider was moving
// Used to modify the standing of avatars (avatars on stationary things stand still) // Used to modify the standing of avatars (avatars on stationary things stand still)
protected bool ColliderIsMoving; public bool ColliderIsMoving;
// Used by BSCharacter to manage standing (and not slipping)
public bool IsStationary;
// Count of collisions for this object // Count of collisions for this object
protected long CollisionAccumulation { get; set; } protected long CollisionAccumulation { get; set; }
@ -293,7 +372,7 @@ public abstract class BSPhysObject : PhysicsActor
protected CollisionEventUpdate CollisionCollection; protected CollisionEventUpdate CollisionCollection;
// Remember collisions from last tick for fancy collision based actions // Remember collisions from last tick for fancy collision based actions
// (like a BSCharacter walking up stairs). // (like a BSCharacter walking up stairs).
protected CollisionEventUpdate CollisionsLastTick; public CollisionEventUpdate CollisionsLastTick;
// The simulation step is telling this object about a collision. // The simulation step is telling this object about a collision.
// Return 'true' if a collision was processed and should be sent up. // Return 'true' if a collision was processed and should be sent up.
@ -424,104 +503,6 @@ public abstract class BSPhysObject : PhysicsActor
public BSActorCollection PhysicalActors; public BSActorCollection PhysicalActors;
// There are some actions that must be performed for a physical object before each simulation step.
// These actions are optional so, rather than scanning all the physical objects and asking them
// if they have anything to do, a physical object registers for an event call before the step is performed.
// This bookkeeping makes it easy to add, remove and clean up after all these registrations.
private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
{
string identifier = op + "-" + id.ToString();
lock (RegisteredPrestepActions)
{
// Clean out any existing action
UnRegisterPreStepAction(op, id);
RegisteredPrestepActions[identifier] = actn;
PhysicsScene.BeforeStep += actn;
}
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
}
// Unregister a pre step action. Safe to call if the action has not been registered.
// Returns 'true' if an action was actually removed
protected bool UnRegisterPreStepAction(string op, uint id)
{
string identifier = op + "-" + id.ToString();
bool removed = false;
lock (RegisteredPrestepActions)
{
if (RegisteredPrestepActions.ContainsKey(identifier))
{
PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
RegisteredPrestepActions.Remove(identifier);
removed = true;
}
}
DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
return removed;
}
protected void UnRegisterAllPreStepActions()
{
lock (RegisteredPrestepActions)
{
foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
{
PhysicsScene.BeforeStep -= kvp.Value;
}
RegisteredPrestepActions.Clear();
}
DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
}
protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
{
string identifier = op + "-" + id.ToString();
lock (RegisteredPoststepActions)
{
// Clean out any existing action
UnRegisterPostStepAction(op, id);
RegisteredPoststepActions[identifier] = actn;
PhysicsScene.AfterStep += actn;
}
DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
}
// Unregister a pre step action. Safe to call if the action has not been registered.
// Returns 'true' if an action was actually removed.
protected bool UnRegisterPostStepAction(string op, uint id)
{
string identifier = op + "-" + id.ToString();
bool removed = false;
lock (RegisteredPoststepActions)
{
if (RegisteredPoststepActions.ContainsKey(identifier))
{
PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
RegisteredPoststepActions.Remove(identifier);
removed = true;
}
}
DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
return removed;
}
protected void UnRegisterAllPostStepActions()
{
lock (RegisteredPoststepActions)
{
foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
{
PhysicsScene.AfterStep -= kvp.Value;
}
RegisteredPoststepActions.Clear();
}
DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
}
// When an update to the physical properties happens, this event is fired to let // When an update to the physical properties happens, this event is fired to let
// different actors to modify the update before it is passed around // different actors to modify the update before it is passed around
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
@ -533,46 +514,6 @@ public abstract class BSPhysObject : PhysicsActor
actions(ref entprop); actions(ref entprop);
} }
private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
{
lock (RegisteredPreUpdatePropertyActions)
{
// Clean out any existing action
UnRegisterPreUpdatePropertyAction(identifier);
RegisteredPreUpdatePropertyActions[identifier] = actn;
OnPreUpdateProperty += actn;
}
DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
}
public bool UnRegisterPreUpdatePropertyAction(string identifier)
{
bool removed = false;
lock (RegisteredPreUpdatePropertyActions)
{
if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
{
OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
RegisteredPreUpdatePropertyActions.Remove(identifier);
removed = true;
}
}
DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
return removed;
}
public void UnRegisterAllPreUpdatePropertyActions()
{
lock (RegisteredPreUpdatePropertyActions)
{
foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
{
OnPreUpdateProperty -= kvp.Value;
}
RegisteredPreUpdatePropertyActions.Clear();
}
DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
}
#endregion // Per Simulation Step actions #endregion // Per Simulation Step actions
// High performance detailed logging routine used by the physical objects. // High performance detailed logging routine used by the physical objects.

View File

@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject
private OMV.Vector3 _position; private OMV.Vector3 _position;
private float _mass; // the mass of this object private float _mass; // the mass of this object
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
private OMV.Vector3 _torque;
private OMV.Vector3 _acceleration; private OMV.Vector3 _acceleration;
private OMV.Quaternion _orientation; private OMV.Quaternion _orientation;
private int _physicsActorType; private int _physicsActorType;
@ -73,16 +70,13 @@ public class BSPrim : BSPhysObject
private int CrossingFailures { get; set; } private int CrossingFailures { get; set; }
public BSDynamics VehicleActor; public BSDynamics VehicleActor;
public string VehicleActorName = "BasicVehicle"; public const string VehicleActorName = "BasicVehicle";
private BSVMotor _targetMotor; public const string HoverActorName = "HoverActor";
private OMV.Vector3 _PIDTarget; public const String LockedAxisActorName = "BSPrim.LockedAxis";
private float _PIDTau; public const string MoveToTargetActorName = "MoveToTargetActor";
public const string SetForceActorName = "SetForceActor";
private BSFMotor _hoverMotor; public const string SetTorqueActorName = "SetTorqueActor";
private float _PIDHoverHeight;
private PIDHoverType _PIDHoverType;
private float _PIDHoverTau;
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@ -95,12 +89,13 @@ public class BSPrim : BSPhysObject
Scale = size; // prims are the size the user wants them to be (different for BSCharactes). Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
_orientation = rotation; _orientation = rotation;
_buoyancy = 0f; _buoyancy = 0f;
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
BaseShape = pbs; BaseShape = pbs;
_isPhysical = pisPhysical; _isPhysical = pisPhysical;
_isVolumeDetect = false; _isVolumeDetect = false;
// We keep a handle to the vehicle actor so we can set vehicle parameters later.
VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName);
PhysicalActors.Add(VehicleActorName, VehicleActor); PhysicalActors.Add(VehicleActorName, VehicleActor);
@ -233,7 +228,7 @@ public class BSPrim : BSPhysObject
// Called at taint time! // Called at taint time!
public override void ZeroMotion(bool inTaintTime) public override void ZeroMotion(bool inTaintTime)
{ {
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
@ -270,19 +265,17 @@ public class BSPrim : BSPhysObject
if (axis.Z != 1) locking.Z = 0f; if (axis.Z != 1) locking.Z = 0f;
LockedAxis = locking; LockedAxis = locking;
if (LockedAxis != LockedAxisFree) EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate()
{ {
PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName);
{ });
// If there is not already an axis locker, make one
if (!PhysicalActors.HasActor(LockedAxisActorName)) // Update parameters so the new actor's Refresh() action is called at the right time.
{ PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID); {
PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName)); UpdatePhysicalParameters();
} });
UpdatePhysicalParameters();
});
}
return; return;
} }
@ -407,9 +400,9 @@ public class BSPrim : BSPhysObject
ZeroMotion(inTaintTime); ZeroMotion(inTaintTime);
ret = true; ret = true;
} }
if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
{ {
_velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
ret = true; ret = true;
} }
if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
@ -506,48 +499,25 @@ public class BSPrim : BSPhysObject
} }
public override OMV.Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return RawForce; }
set { set {
_force = value; RawForce = value;
if (_force != OMV.Vector3.Zero) EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
{ {
// If the force is non-zero, it must be reapplied each tick because return new BSActorSetForce(PhysicsScene, this, SetForceActorName);
// Bullet clears the forces applied last frame. });
RegisterPreStepAction("BSPrim.setForce", LocalID,
delegate(float timeStep)
{
if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
{
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
return;
}
DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
if (PhysBody.HasPhysicalBody)
{
PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
ActivateIfPhysical(false);
}
}
);
}
else
{
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
}
} }
} }
public override int VehicleType { public override int VehicleType {
get { get {
return (int)VehicleActor.Type; // if we are a vehicle, return that type return (int)VehicleActor.Type;
} }
set { set {
Vehicle type = (Vehicle)value; Vehicle type = (Vehicle)value;
PhysicsScene.TaintedObject("setVehicleType", delegate() PhysicsScene.TaintedObject("setVehicleType", delegate()
{ {
// Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type. // Vehicle code changes the parameters for this vehicle type.
VehicleActor.ProcessTypeChange(type); VehicleActor.ProcessTypeChange(type);
ActivateIfPhysical(false); ActivateIfPhysical(false);
@ -670,63 +640,40 @@ public class BSPrim : BSPhysObject
} }
} }
} }
public override OMV.Vector3 RawVelocity
{
get { return _velocity; }
set { _velocity = value; }
}
public override OMV.Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
_velocity = value; RawVelocity = value;
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
{ {
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
}); });
} }
} }
public override OMV.Vector3 ForceVelocity { public override OMV.Vector3 ForceVelocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
_velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
ActivateIfPhysical(false); ActivateIfPhysical(false);
} }
} }
} }
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return RawTorque; }
set { set {
_torque = value; RawTorque = value;
if (_torque != OMV.Vector3.Zero) EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
{ {
// If the torque is non-zero, it must be reapplied each tick because return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName);
// Bullet clears the forces applied last frame. });
RegisterPreStepAction("BSPrim.setTorque", LocalID, DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
delegate(float timeStep)
{
if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
{
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
return;
}
if (PhysBody.HasPhysicalBody)
AddAngularForce(_torque, false, true);
}
);
}
else
{
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
}
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
} }
} }
public override OMV.Vector3 Acceleration { public override OMV.Vector3 Acceleration {
@ -839,7 +786,6 @@ public class BSPrim : BSPhysObject
MakeDynamic(IsStatic); MakeDynamic(IsStatic);
// Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
VehicleActor.Refresh();
PhysicalActors.Refresh(); PhysicalActors.Refresh();
// Arrange for collision events if the simulator wants them // Arrange for collision events if the simulator wants them
@ -909,7 +855,7 @@ public class BSPrim : BSPhysObject
// For good measure, make sure the transform is set through to the motion state // For good measure, make sure the transform is set through to the motion state
ForcePosition = _position; ForcePosition = _position;
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
ForceRotationalVelocity = _rotationalVelocity; ForceRotationalVelocity = _rotationalVelocity;
// A dynamic object has mass // A dynamic object has mass
@ -966,15 +912,6 @@ public class BSPrim : BSPhysObject
} }
} }
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
// they need waking up when parameters are changed.
// Called in taint-time!!
private void ActivateIfPhysical(bool forceIt)
{
if (IsPhysical && PhysBody.HasPhysicalBody)
PhysicsScene.PE.Activate(PhysBody, forceIt);
}
// Turn on or off the flag controlling whether collision events are returned to the simulator. // Turn on or off the flag controlling whether collision events are returned to the simulator.
private void EnableCollisions(bool wantsCollisionEvents) private void EnableCollisions(bool wantsCollisionEvents)
{ {
@ -1096,78 +1033,13 @@ public class BSPrim : BSPhysObject
} }
} }
// Used for MoveTo
public override OMV.Vector3 PIDTarget {
set
{
// TODO: add a sanity check -- don't move more than a region or something like that.
_PIDTarget = value;
}
}
public override float PIDTau {
set { _PIDTau = value; }
}
public override bool PIDActive { public override bool PIDActive {
set { set {
if (value) base.MoveToTargetActive = value;
EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
{ {
// We're taking over after this. return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName);
ZeroMotion(true); });
_targetMotor = new BSVMotor("BSPrim.PIDTarget",
_PIDTau, // timeScale
BSMotor.Infinite, // decay time scale
BSMotor.InfiniteVector, // friction timescale
1f // efficiency
);
_targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
_targetMotor.SetTarget(_PIDTarget);
_targetMotor.SetCurrent(RawPosition);
/*
_targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
_targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
_targetMotor.SetTarget(_PIDTarget);
_targetMotor.SetCurrent(RawPosition);
_targetMotor.TimeScale = _PIDTau;
_targetMotor.Efficiency = 1f;
*/
RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
{
if (!IsPhysicallyActive)
{
UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
return;
}
OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
// 'movePosition' is where we'd like the prim to be at this moment.
OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
// If we are very close to our target, turn off the movement motor.
if (_targetMotor.ErrorIsZero())
{
DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
LocalID, movePosition, RawPosition, Mass);
ForcePosition = _targetMotor.TargetValue;
_targetMotor.Enabled = false;
}
else
{
_position = movePosition;
PositionSanityCheck(true /* intaintTime */);
ForcePosition = _position;
}
DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
});
}
else
{
// Stop any targetting
UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
}
} }
} }
@ -1175,87 +1047,13 @@ public class BSPrim : BSPhysObject
// Hover Height will override MoveTo target's Z // Hover Height will override MoveTo target's Z
public override bool PIDHoverActive { public override bool PIDHoverActive {
set { set {
if (value) base.HoverActive = value;
EnableActor(HoverActive, HoverActorName, delegate()
{ {
// Turning the target on return new BSActorHover(PhysicsScene, this, HoverActorName);
_hoverMotor = new BSFMotor("BSPrim.Hover", });
_PIDHoverTau, // timeScale
BSMotor.Infinite, // decay time scale
BSMotor.Infinite, // friction timescale
1f // efficiency
);
_hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
_hoverMotor.SetCurrent(RawPosition.Z);
_hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
{
// Don't do hovering while the object is selected.
if (!IsPhysicallyActive)
return;
_hoverMotor.SetCurrent(RawPosition.Z);
_hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
float targetHeight = _hoverMotor.Step(timeStep);
// 'targetHeight' is where we'd like the Z of the prim to be at this moment.
// Compute the amount of force to push us there.
float moveForce = (targetHeight - RawPosition.Z) * Mass;
// Undo anything the object thinks it's doing at the moment
moveForce = -RawVelocity.Z * Mass;
PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
});
}
else
{
UnRegisterPreStepAction("BSPrim.Hover", LocalID);
}
} }
} }
public override float PIDHoverHeight {
set { _PIDHoverHeight = value; }
}
public override PIDHoverType PIDHoverType {
set { _PIDHoverType = value; }
}
public override float PIDHoverTau {
set { _PIDHoverTau = value; }
}
// Based on current position, determine what we should be hovering at now.
// Must recompute often. What if we walked offa cliff>
private float ComputeCurrentPIDHoverHeight()
{
float ret = _PIDHoverHeight;
float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
switch (_PIDHoverType)
{
case PIDHoverType.Ground:
ret = groundHeight + _PIDHoverHeight;
break;
case PIDHoverType.GroundAndWater:
float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
if (groundHeight > waterHeight)
{
ret = groundHeight + _PIDHoverHeight;
}
else
{
ret = waterHeight + _PIDHoverHeight;
}
break;
}
return ret;
}
// For RotLookAt
public override OMV.Quaternion APIDTarget { set { return; } }
public override bool APIDActive { set { return; } }
public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } }
public override void AddForce(OMV.Vector3 force, bool pushforce) { public override void AddForce(OMV.Vector3 force, bool pushforce) {
// Per documentation, max force is limited. // Per documentation, max force is limited.
@ -1324,10 +1122,8 @@ public class BSPrim : BSPhysObject
} }
} }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { // BSPhysObject.AddAngularForce()
AddAngularForce(force, pushforce, false); public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
}
public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
{ {
if (force.IsFinite()) if (force.IsFinite())
{ {
@ -1661,7 +1457,7 @@ public class BSPrim : BSPhysObject
{ {
// Create the correct physical representation for this type of object. // Create the correct physical representation for this type of object.
// Updates base.PhysBody and base.PhysShape with the new information. // Updates base.PhysBody and base.PhysShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody)
{ {
// Called if the current prim body is about to be destroyed. // Called if the current prim body is about to be destroyed.
@ -1675,9 +1471,9 @@ public class BSPrim : BSPhysObject
return; return;
} }
// Called at taint-time
protected virtual void RemoveBodyDependencies() protected virtual void RemoveBodyDependencies()
{ {
VehicleActor.RemoveBodyDependencies();
PhysicalActors.RemoveBodyDependencies(); PhysicalActors.RemoveBodyDependencies();
} }
@ -1685,6 +1481,7 @@ public class BSPrim : BSPhysObject
// the world that things have changed. // the world that things have changed.
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
// Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
TriggerPreUpdatePropertyAction(ref entprop); TriggerPreUpdatePropertyAction(ref entprop);
// DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
@ -1694,8 +1491,8 @@ public class BSPrim : BSPhysObject
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
// DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
// very sensitive to velocity changes. // very sensitive to velocity changes.
if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
_velocity = entprop.Velocity; RawVelocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
@ -1705,7 +1502,7 @@ public class BSPrim : BSPhysObject
if (PositionSanityCheck(true /* inTaintTime */ )) if (PositionSanityCheck(true /* inTaintTime */ ))
{ {
entprop.Position = _position; entprop.Position = _position;
entprop.Velocity = _velocity; entprop.Velocity = RawVelocity;
entprop.RotationalVelocity = _rotationalVelocity; entprop.RotationalVelocity = _rotationalVelocity;
entprop.Acceleration = _acceleration; entprop.Acceleration = _acceleration;
} }
@ -1717,16 +1514,8 @@ public class BSPrim : BSPhysObject
LastEntityProperties = CurrentEntityProperties; LastEntityProperties = CurrentEntityProperties;
CurrentEntityProperties = entprop; CurrentEntityProperties = entprop;
// Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims.
base.RequestPhysicsterseUpdate(); base.RequestPhysicsterseUpdate();
/*
else
{
// For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
} }
} }
} }

View File

@ -163,6 +163,15 @@ public class BSPrimLinkable : BSPrimDisplaced
// TODO: this will have to change when linksets are articulated. // TODO: this will have to change when linksets are articulated.
base.UpdateProperties(entprop); base.UpdateProperties(entprop);
} }
/*
else
{
// For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
// The linkset might like to know about changing locations // The linkset might like to know about changing locations
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
} }

View File

@ -316,6 +316,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
break; break;
case "bulletxna": case "bulletxna":
ret = new BSAPIXNA(engineName, this); ret = new BSAPIXNA(engineName, this);
BSParam.ShouldUseBulletHACD = false;
break; break;
} }

View File

@ -722,7 +722,7 @@ public sealed class BSShapeCollection : IDisposable
// Remove usage of the previous shape. // Remove usage of the previous shape.
DereferenceShape(prim.PhysShape, shapeCallback); DereferenceShape(prim.PhysShape, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod);
// It might not have been created if we're waiting for an asset. // It might not have been created if we're waiting for an asset.
newShape = VerifyMeshCreated(newShape, prim); newShape = VerifyMeshCreated(newShape, prim);
@ -733,7 +733,7 @@ public sealed class BSShapeCollection : IDisposable
} }
List<ConvexResult> m_hulls; List<ConvexResult> m_hulls;
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{ {
BulletShape newShape = new BulletShape(); BulletShape newShape = new BulletShape();
@ -747,115 +747,152 @@ public sealed class BSShapeCollection : IDisposable
} }
else else
{ {
// Build a new hull in the physical world. if (BSParam.ShouldUseBulletHACD)
// Pass true for physicalness as this prevents the creation of bounding box which is not needed
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
if (meshData != null)
{ {
DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID);
int[] indices = meshData.getIndexListAsInt(); MeshDesc meshDesc;
List<OMV.Vector3> vertices = meshData.getVertexList(); if (!Meshes.TryGetValue(newHullKey, out meshDesc))
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{ {
convIndices.Add(indices[ii]); // That's odd because the mesh should have been created before the hull
} // but, since it doesn't exist, create it.
foreach (OMV.Vector3 vv in vertices) newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod);
{ DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; if (newShape.HasPhysicalShape)
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
{
// Simple primitive shapes we know are convex so they are better implemented with
// fewer hulls.
// Check for simple shape (prim without cuts) and reduce split parameter if so.
if (PrimHasNoCuts(pbs))
{ {
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; ReferenceShape(newShape);
Meshes.TryGetValue(newHullKey, out meshDesc);
} }
} }
if (meshDesc.shape.HasPhysicalShape)
// setup and do convex hull conversion
m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
dcomp.mDepth = maxDepthSplit;
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
// Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = m_hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in m_hulls)
{ {
totalVertices += 4; // add four for the vertex count and centroid HACDParams parms;
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
} parms.minClusters = BSParam.BHullMinClusters;
float[] convHulls = new float[totalVertices]; parms.compacityWeight = BSParam.BHullCompacityWeight;
parms.volumeWeight = BSParam.BHullVolumeWeight;
parms.concavity = BSParam.BHullConcavity;
parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
convHulls[0] = (float)hullCount; DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
int jj = 1; newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms);
foreach (ConvexResult cr in m_hulls) DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
} }
// create the hull data structure in Bullet DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
} }
} if (!newShape.HasPhysicalShape)
{
// Build a new hull in the physical world.
// Pass true for physicalness as this prevents the creation of bounding box which is not needed
IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
if (meshData != null)
{
int[] indices = meshData.getIndexListAsInt();
List<OMV.Vector3> vertices = meshData.getVertexList();
newShape.shapeKey = newHullKey; //format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{
convIndices.Add(indices[ii]);
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
{
// Simple primitive shapes we know are convex so they are better implemented with
// fewer hulls.
// Check for simple shape (prim without cuts) and reduce split parameter if so.
if (PrimHasNoCuts(pbs))
{
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
}
}
// setup and do convex hull conversion
m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
dcomp.mDepth = maxDepthSplit;
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
// Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = m_hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in m_hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in m_hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
}
// create the hull data structure in Bullet
newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
}
}
newShape.shapeKey = newHullKey;
}
return newShape; return newShape;
} }

View File

@ -213,13 +213,13 @@ public sealed class BSTerrainManager : IDisposable
}); });
} }
// Another region is calling this region passing a terrain. // Another region is calling this region and passing a terrain.
// A region that is not the mega-region root will pass its terrain to the root region so the root region // A region that is not the mega-region root will pass its terrain to the root region so the root region
// physics engine will have all the terrains. // physics engine will have all the terrains.
private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
{ {
// Since we are called by another region's thread, the action must be rescheduled onto our processing thread. // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + m_worldOffset.ToString(), 0, delegate() PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
{ {
UpdateTerrain(id, heightMap, minCoords, maxCoords); UpdateTerrain(id, heightMap, minCoords, maxCoords);
}); });
@ -306,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable
newTerrainID = ++m_terrainCount; newTerrainID = ++m_terrainCount;
DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrains.Add(terrainRegionBase, newTerrainPhys);

View File

@ -6,7 +6,6 @@ Enable vehicle border crossings (at least as poorly as ODE)
Terrain skirts Terrain skirts
Avatar created in previous region and not new region when crossing border Avatar created in previous region and not new region when crossing border
Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
Lock axis
Deleting a linkset while standing on the root will leave the physical shape of the root behind. Deleting a linkset while standing on the root will leave the physical shape of the root behind.
Not sure if it is because standing on it. Done with large prim linksets. Not sure if it is because standing on it. Done with large prim linksets.
Linkset child rotations. Linkset child rotations.
@ -344,3 +343,5 @@ 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 that angular motion specified around Z moves in the vehicle coordinates.
DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
Nebadon vehicles turning funny in arena (DONE) Nebadon vehicles turning funny in arena (DONE)
Lock axis (DONE 20130401)

View File

@ -27,6 +27,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
@ -34,10 +36,10 @@ using OpenSim.Region.CoreModules.World.Land;
namespace OpenSim.Region.RegionCombinerModule namespace OpenSim.Region.RegionCombinerModule
{ {
public class RegionCombinerLargeLandChannel : ILandChannel public class RegionCombinerLargeLandChannel : ILandChannel
{ {
// private static readonly ILog m_log = // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private RegionData RegData; private RegionData RegData;
private ILandChannel RootRegionLandChannel; private ILandChannel RootRegionLandChannel;
private readonly List<RegionData> RegionConnections; private readonly List<RegionData> RegionConnections;
@ -75,40 +77,51 @@ public class RegionCombinerLargeLandChannel : ILandChannel
public ILandObject GetLandObject(int x, int y) public ILandObject GetLandObject(int x, int y)
{ {
//m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); return GetLandObject((float)x, (float)y);
if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) // m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
{ //
return RootRegionLandChannel.GetLandObject(x, y); // if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
} // {
else // return RootRegionLandChannel.GetLandObject(x, y);
{ // }
int offsetX = (x / (int)Constants.RegionSize); // else
int offsetY = (y / (int)Constants.RegionSize); // {
offsetX *= (int)Constants.RegionSize; // int offsetX = (x / (int)Constants.RegionSize);
offsetY *= (int)Constants.RegionSize; // int offsetY = (y / (int)Constants.RegionSize);
// offsetX *= (int)Constants.RegionSize;
foreach (RegionData regionData in RegionConnections) // offsetY *= (int)Constants.RegionSize;
{ //
if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) // foreach (RegionData regionData in RegionConnections)
{ // {
return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); // if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
} // {
} // m_log.DebugFormat(
ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); // "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
obj.LandData.Name = "NO LAND"; // regionData.RegionScene.Name, offsetX, offsetY);
return obj; //
} // return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
// }
// }
// //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
// //obj.LandData.Name = "NO LAND";
// //return obj;
// }
//
// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
//
// return null;
} }
public ILandObject GetLandObject(int localID) public ILandObject GetLandObject(int localID)
{ {
// XXX: Possibly should be looking in every land channel, not just the root.
return RootRegionLandChannel.GetLandObject(localID); return RootRegionLandChannel.GetLandObject(localID);
} }
public ILandObject GetLandObject(float x, float y) public ILandObject GetLandObject(float x, float y)
{ {
//m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); // m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y);
if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
{ {
@ -125,14 +138,22 @@ public class RegionCombinerLargeLandChannel : ILandChannel
{ {
if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
{ {
// m_log.DebugFormat(
// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
// regionData.RegionScene.Name, offsetX, offsetY);
return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
} }
} }
ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); // ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
obj.LandData.Name = "NO LAND"; // obj.LandData.Name = "NO LAND";
return obj; // return obj;
} }
// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
return null;
} }
public bool IsForcefulBansAllowed() public bool IsForcefulBansAllowed()

View File

@ -528,8 +528,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{ {
File.Delete(savedState); File.Delete(savedState);
} }
catch(Exception) catch (Exception e)
{ {
m_log.Warn(
string.Format(
"[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ",
ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name),
e);
} }
} }

View File

@ -137,10 +137,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
userID, sessionID, secureSessionID); userID, sessionID, secureSessionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddSession" }, { "RequestMethod", "AddSession" },
{ "UserID", userID.ToString() } { "UserID", userID.ToString() }
}; };
if (sessionID != UUID.Zero) if (sessionID != UUID.Zero)
{ {
requestArgs["SessionID"] = sessionID.ToString(); requestArgs["SessionID"] = sessionID.ToString();
@ -158,13 +159,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LogoutAgent(UUID sessionID) public bool LogoutAgent(UUID sessionID)
{ {
// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "RemoveSession" }, { "RequestMethod", "RemoveSession" },
{ "SessionID", sessionID.ToString() } { "SessionID", sessionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -177,13 +178,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LogoutRegionAgents(UUID regionID) public bool LogoutRegionAgents(UUID regionID)
{ {
// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "RemoveSessions" }, { "RequestMethod", "RemoveSessions" },
{ "SceneID", regionID.ToString() } { "SceneID", regionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -202,49 +203,46 @@ namespace OpenSim.Services.Connectors.SimianGrid
public PresenceInfo GetAgent(UUID sessionID) public PresenceInfo GetAgent(UUID sessionID)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
if (sessionResponse == null)
NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetSession" }, m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
{ "SessionID", sessionID.ToString() } return null;
};
OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (sessionResponse["Success"].AsBoolean())
{
UUID userID = sessionResponse["UserID"].AsUUID();
m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() }
};
OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (userResponse["Success"].AsBoolean())
return ResponseToPresenceInfo(sessionResponse, userResponse);
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
}
else
{
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString());
} }
return null; UUID userID = sessionResponse["UserID"].AsUUID();
OSDMap userResponse = GetUserData(userID);
if (userResponse == null)
{
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
return null;
}
return ResponseToPresenceInfo(sessionResponse);
} }
public PresenceInfo[] GetAgents(string[] userIDs) public PresenceInfo[] GetAgents(string[] userIDs)
{ {
List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length); List<PresenceInfo> presences = new List<PresenceInfo>();
for (int i = 0; i < userIDs.Length; i++) NameValueCollection requestArgs = new NameValueCollection
{ {
UUID userID; { "RequestMethod", "GetSessions" },
if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) { "UserIDList", String.Join(",",userIDs) }
presences.AddRange(GetSessions(userID)); };
OSDMap sessionListResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (! sessionListResponse["Success"].AsBoolean())
{
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
return null;
}
OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
for (int i = 0; i < sessionList.Count; i++)
{
OSDMap sessionInfo = sessionList[i] as OSDMap;
presences.Add(ResponseToPresenceInfo(sessionInfo));
} }
return presences.ToArray(); return presences.ToArray();
@ -262,7 +260,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
// Remove the session to mark this user offline // Remove the session to mark this user offline
if (!LogoutAgent(sessionID)) if (!LogoutAgent(sessionID))
@ -270,11 +268,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
// Save our last position as user data // Save our last position as user data
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddUserData" }, { "RequestMethod", "AddUserData" },
{ "UserID", userID.ToString() }, { "UserID", userID.ToString() },
{ "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -287,14 +285,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddUserData" }, { "RequestMethod", "AddUserData" },
{ "UserID", userID.ToString() }, { "UserID", userID.ToString() },
{ "HomeLocation", SerializeLocation(regionID, position, lookAt) } { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -312,23 +310,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
public GridUserInfo GetGridUserInfo(string user) public GridUserInfo GetGridUserInfo(string user)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
UUID userID = new UUID(user); UUID userID = new UUID(user);
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); OSDMap userResponse = GetUserData(userID);
if (userResponse != null)
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() }
};
OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (userResponse["Success"].AsBoolean())
return ResponseToGridUserInfo(userResponse); return ResponseToGridUserInfo(userResponse);
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID,userResponse["Message"].AsString());
return null; return null;
} }
@ -338,65 +327,49 @@ namespace OpenSim.Services.Connectors.SimianGrid
private OSDMap GetUserData(UUID userID) private OSDMap GetUserData(UUID userID)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetUser" }, { "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() } { "UserID", userID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
if (response["Success"].AsBoolean() && response["User"] is OSDMap) if (response["Success"].AsBoolean() && response["User"] is OSDMap)
return response; return response;
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString());
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
return null; return null;
} }
private List<PresenceInfo> GetSessions(UUID userID) private OSDMap GetSessionDataFromSessionID(UUID sessionID)
{ {
List<PresenceInfo> presences = new List<PresenceInfo>(1); NameValueCollection requestArgs = new NameValueCollection
OSDMap userResponse = GetUserData(userID);
if (userResponse != null)
{
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID);
NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetSession" }, { "RequestMethod", "GetSession" },
{ "UserID", userID.ToString() } { "SessionID", sessionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
if (response["Success"].AsBoolean()) if (response["Success"].AsBoolean())
{ return response;
PresenceInfo presence = ResponseToPresenceInfo(response, userResponse);
if (presence != null)
presences.Add(presence);
}
// else
// {
// m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString());
// }
}
return presences; m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
return null;
} }
private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
{ {
// Save our current location as session data // Save our current location as session data
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "UpdateSession" }, { "RequestMethod", "UpdateSession" },
{ "SessionID", sessionID.ToString() }, { "SessionID", sessionID.ToString() },
{ "SceneID", regionID.ToString() }, { "SceneID", regionID.ToString() },
{ "ScenePosition", lastPosition.ToString() }, { "ScenePosition", lastPosition.ToString() },
{ "SceneLookAt", lastLookAt.ToString() } { "SceneLookAt", lastLookAt.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -407,7 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
return success; return success;
} }
private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
{ {
if (sessionResponse == null) if (sessionResponse == null)
return null; return null;

View File

@ -43,9 +43,14 @@
; Sets the method that OpenSim will use to fire asynchronous ; Sets the method that OpenSim will use to fire asynchronous
; events. Valid values are UnsafeQueueUserWorkItem, ; events. Valid values are UnsafeQueueUserWorkItem,
; QueueUserWorkItem, BeginInvoke, SmartThreadPool, and Thread. ; QueueUserWorkItem, BeginInvoke, SmartThreadPool, and Thread.
;
; SmartThreadPool is reported to work well on Mono/Linux, but ; SmartThreadPool is reported to work well on Mono/Linux, but
; UnsafeQueueUserWorkItem has been benchmarked with better ; UnsafeQueueUserWorkItem has been benchmarked with better
; performance on .NET/Windows ; performance on .NET/Windows
;
; UnsafeQueueUserWorkItem refers to the fact that the code creating the event could elevate its security
; privileges. However, as calling code is trusted anyway this is safe (if you set
; TrustedBinaries = true in the [XEngine] section then you already have to trust that incoming code for other reasons).
async_call_method = SmartThreadPool async_call_method = SmartThreadPool
; Max threads to allocate on the FireAndForget thread pool ; Max threads to allocate on the FireAndForget thread pool

View File

@ -1,6 +1,8 @@
<configuration> <configuration>
<dllmap os="windows" cpu="x86" dll="BulletSim" target="lib32/BulletSim" /> <dllmap os="windows" cpu="x86" dll="BulletSim" target="lib32/BulletSim" />
<dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="lib64/BulletSim" /> <dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="lib64/BulletSim" />
<dllmap os="osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.dylib" />
<dllmap os="osx" cpu="x86-64,ia64" dll="BulletSim" target="lib32/libBulletSim.dylib" />
<dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.so" /> <dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.so" />
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="lib64/libBulletSim.so" /> <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="lib64/libBulletSim.so" />
</configuration> </configuration>

Binary file not shown.

BIN
bin/lib32/libBulletSim.dylib Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.