Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
commit
aab2b032aa
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 && 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},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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* 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 && 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},BSActorMoveToTarget,refresh", m_controllingPrim.LocalID);
|
||||||
|
|
||||||
|
// 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("BSPrim.PIDTarget",
|
||||||
|
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},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
|
||||||
|
m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
|
||||||
|
m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_controllingPrim.ForcePosition = movePosition;
|
||||||
|
}
|
||||||
|
m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,45 @@ 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
|
||||||
|
theActor.Enabled = enableActor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The actor does not exist. If it should, create it.
|
||||||
|
if (enableActor)
|
||||||
|
{
|
||||||
|
theActor = creator();
|
||||||
|
PhysicalActors.Add(actorName, theActor);
|
||||||
|
theActor.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Collisions
|
#region Collisions
|
||||||
|
|
||||||
|
@ -255,7 +326,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 +366,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 +497,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 +508,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.
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
UUID userID = sessionResponse["UserID"].AsUUID();
|
||||||
|
OSDMap userResponse = GetUserData(userID);
|
||||||
|
if (userResponse == null)
|
||||||
{
|
{
|
||||||
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString());
|
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -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.
Loading…
Reference in New Issue