From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Region/PhysicsModules/BulletS/BSCharacter.cs | 323 ++++++++++++--------- 1 file changed, 186 insertions(+), 137 deletions(-) (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs') diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs index 83fc3a6..d182c34 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -40,7 +40,6 @@ public sealed class BSCharacter : BSPhysObject private static readonly string LogHeader = "[BULLETS CHAR]"; // private bool _stopped; - private OMV.Vector3 _size; private bool _grabbed; private bool _selected; private float _mass; @@ -53,19 +52,21 @@ public sealed class BSCharacter : BSPhysObject private bool _setAlwaysRun; private bool _throttleUpdates; private bool _floatOnWater; - private OMV.Vector3 _rotationalVelocity; private bool _kinematic; private float _buoyancy; + private OMV.Vector3 _size; + private float _footOffset; + private BSActorAvatarMove m_moveActor; private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; private OMV.Vector3 _PIDTarget; private float _PIDTau; -// public override OMV.Vector3 RawVelocity -// { get { return base.RawVelocity; } -// set { +// public override OMV.Vector3 RawVelocity +// { get { return base.RawVelocity; } +// set { // if (value != base.RawVelocity) // Util.PrintCallStack(); // Console.WriteLine("Set rawvel to {0}", value); @@ -76,12 +77,12 @@ public sealed class BSCharacter : BSPhysObject public override bool IsIncomplete { get { return false; } } public BSCharacter( - uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying) + uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; - RawPosition = pos; + RawPosition = pos; _flying = isFlying; RawOrientation = OMV.Quaternion.Identity; @@ -89,22 +90,15 @@ public sealed class BSCharacter : BSPhysObject _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; Density = BSParam.AvatarDensity; + _isPhysical = true; - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - _size = size; - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; - - // The dimensions of the physical capsule are kept in the scale. - // Physics creates a unit capsule which is scaled by the physics engine. - Scale = ComputeAvatarScale(_size); - // set _avatarVolume and _mass based on capsule size, _density and Scale - ComputeAvatarVolumeAndMass(); + // Adjustments for zero X and Y made in Size() + // This also computes avatar scale, volume, and mass + SetAvatarSize(size, footOffset, true /* initializing */); DetailLog( "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", - LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel); + LocalID, Size, Scale, Density, _avatarVolume, RawMass, pos, vel); // do actual creation in taint time PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() @@ -208,45 +202,68 @@ public sealed class BSCharacter : BSPhysObject public override OMV.Vector3 Size { get { - // Avatar capsule size is kept in the scale parameter. return _size; } set { - // This is how much the avatar size is changing. Positive means getting bigger. - // The avatar altitude must be adjusted for this change. - float heightChange = value.Z - _size.Z; + setAvatarSize(value, _footOffset); + } + } + + // OpenSim 0.9 introduces a common avatar size computation + public override void setAvatarSize(OMV.Vector3 size, float feetOffset) + { + SetAvatarSize(size, feetOffset, false /* initializing */); + } - _size = value; + // Internal version that, if initializing, doesn't do all the updating of the physics engine + public void SetAvatarSize(OMV.Vector3 size, float feetOffset, bool initializing) + { + OMV.Vector3 newSize = size; + if (newSize.IsFinite()) + { // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; + if (newSize.X == 0f) newSize.X = BSParam.AvatarCapsuleDepth; + if (newSize.Y == 0f) newSize.Y = BSParam.AvatarCapsuleWidth; - Scale = ComputeAvatarScale(_size); - ComputeAvatarVolumeAndMass(); - DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, Density, _avatarVolume, RawMass); + if (newSize.X < 0.01f) newSize.X = 0.01f; + if (newSize.Y < 0.01f) newSize.Y = 0.01f; + if (newSize.Z < 0.01f) newSize.Z = BSParam.AvatarCapsuleHeight; + } + else + { + newSize = new OMV.Vector3(BSParam.AvatarCapsuleDepth, BSParam.AvatarCapsuleWidth, BSParam.AvatarCapsuleHeight); + } - PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() - { - if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) - { - PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); - UpdatePhysicalMassProperties(RawMass, true); + // This is how much the avatar size is changing. Positive means getting bigger. + // The avatar altitude must be adjusted for this change. + float heightChange = newSize.Z - Size.Z; - // Adjust the avatar's position to account for the increase/decrease in size - ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + _size = newSize; - // Make sure this change appears as a property update event - PhysScene.PE.PushUpdate(PhysBody); - } - }); + Scale = ComputeAvatarScale(Size); + ComputeAvatarVolumeAndMass(); + DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", + LocalID, _size, Scale, Density, _avatarVolume, RawMass); - } + PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() + { + if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) + { + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + UpdatePhysicalMassProperties(RawMass, true); + + // Adjust the avatar's position to account for the increase/decrease in size + ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + + // Make sure this change appears as a property update event + PhysScene.PE.PushUpdate(PhysBody); + } + }); } - public override PrimitiveBaseShape Shape + public override PrimitiveBaseShape Shape { set { BaseShape = value; } } @@ -273,7 +290,7 @@ public sealed class BSCharacter : BSPhysObject { RawVelocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; + RawRotationalVelocity = OMV.Vector3.Zero; // Zero some other properties directly into the physics engine PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() @@ -285,7 +302,7 @@ public sealed class BSCharacter : BSPhysObject public override void ZeroAngularMotion(bool inTaintTime) { - _rotationalVelocity = OMV.Vector3.Zero; + RawRotationalVelocity = OMV.Vector3.Zero; PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { @@ -300,7 +317,7 @@ public sealed class BSCharacter : BSPhysObject } - public override void LockAngularMotion(OMV.Vector3 axis) { return; } + public override void LockAngularMotion(byte axislocks) { return; } public override OMV.Vector3 Position { get { @@ -333,7 +350,6 @@ public sealed class BSCharacter : BSPhysObject } } - // Check that the current position is sane and, if not, modify the position to make it so. // Check for being below terrain or on water. // Returns 'true' of the position was made sane by some action. @@ -433,6 +449,7 @@ public sealed class BSCharacter : BSPhysObject public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } + // PhysicsActor.TargetVelocity // Sets the target in the motor. This starts the changing of the avatar's velocity. public override OMV.Vector3 TargetVelocity { @@ -443,43 +460,51 @@ public sealed class BSCharacter : BSPhysObject set { DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); - m_targetVelocity = value; OMV.Vector3 targetVel = value; - if (_setAlwaysRun && !_flying) - targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); + if (!_flying) + { + if (_setAlwaysRun) + targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); + else + if (BSParam.AvatarWalkVelocityFactor != 1f) + targetVel *= new OMV.Vector3(BSParam.AvatarWalkVelocityFactor, BSParam.AvatarWalkVelocityFactor, 1f); + } + base.m_targetVelocity = targetVel; if (m_moveActor != null) - m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, base.m_targetVelocity, false /* inTaintTime */); } } // Directly setting velocity means this is what the user really wants now. public override OMV.Vector3 Velocity { get { return RawVelocity; } set { - RawVelocity = value; - OMV.Vector3 vel = RawVelocity; - - DetailLog("{0}: set Velocity = {1}", LocalID, value); - - PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() + if (m_moveActor != null) { - if (m_moveActor != null) - m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */); + // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); + } + base.Velocity = value; + } + } - DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel); - ForceVelocity = vel; - }); + // SetMomentum just sets the velocity without a target. We need to stop the movement actor if a character. + public override void SetMomentum(OMV.Vector3 momentum) + { + if (m_moveActor != null) + { + // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); } + base.SetMomentum(momentum); } public override OMV.Vector3 ForceVelocity { get { return RawVelocity; } set { - PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); -// Util.PrintCallStack(); - DetailLog("{0}: set ForceVelocity = {1}", LocalID, value); + DetailLog("{0},BSCharacter.ForceVelocity.set={1}", LocalID, value); - RawVelocity = value; + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); PhysScene.PE.Activate(PhysBody, true); } @@ -600,14 +625,6 @@ public sealed class BSCharacter : BSPhysObject }); } } - public override OMV.Vector3 RotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } - public override OMV.Vector3 ForceRotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } public override bool Kinematic { get { return _kinematic; } set { _kinematic = value; } @@ -626,8 +643,6 @@ public sealed class BSCharacter : BSPhysObject public override float ForceBuoyancy { get { return _buoyancy; } set { - PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); - _buoyancy = value; DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); // Buoyancy is faked by changing the gravity applied to the object @@ -652,14 +667,24 @@ public sealed class BSCharacter : BSPhysObject 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. - OMV.Vector3 addForce = force / PhysScene.LastTimeStep; - AddForce(addForce, pushforce, false); + OMV.Vector3 addForce = force; + + // The interaction of this force with the simulator rate and collision occurance is tricky. + // ODE multiplies the force by 100 + // ubODE multiplies the force by 5.3 + // BulletSim, after much in-world testing, thinks it gets a similar effect by multiplying mass*0.315f + // This number could be a feature of friction or timing, but it seems to move avatars the same as ubODE + addForce *= Mass * BSParam.AvatarAddForcePushFactor; + + DetailLog("{0},BSCharacter.addForce,call,force={1},addForce={2},push={3},mass={4}", LocalID, force, addForce, pushforce, Mass); + AddForce(false, addForce); } - public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + + public override void AddForce(bool inTaintTime, OMV.Vector3 force) { if (force.IsFinite()) { OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); - // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); + // DetailLog("{0},BSCharacter.addForce,call,force={1},push={2},inTaint={3}", LocalID, addForce, pushforce, inTaintTime); PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() { @@ -667,7 +692,15 @@ public sealed class BSCharacter : BSPhysObject // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); if (PhysBody.HasPhysicalBody) { + // Bullet adds this central force to the total force for this tick. + // Deep down in Bullet: + // linearVelocity += totalForce / mass * timeStep; PhysScene.PE.ApplyCentralForce(PhysBody, addForce); + PhysScene.PE.Activate(PhysBody, true); + } + if (m_moveActor != null) + { + m_moveActor.SuppressStationayCheckUntilLowVelocity(); } }); } @@ -678,65 +711,74 @@ public sealed class BSCharacter : BSPhysObject } } - public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { - } - public override void SetMomentum(OMV.Vector3 momentum) { + public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) { } + // The avatar's physical shape (whether capsule or cube) is unit sized. BulletSim sets + // the scale of that unit shape to create the avatars full size. private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) { OMV.Vector3 newScale = size; - // Bullet's capsule total height is the "passed height + radius * 2"; - // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) - // The number we pass in for 'scaling' is the multiplier to get that base - // shape to be the size desired. - // So, when creating the scale for the avatar height, we take the passed height - // (size.Z) and remove the caps. - // An oddity of the Bullet capsule implementation is that it presumes the Y - // dimension is the radius of the capsule. Even though some of the code allows - // for a asymmetrical capsule, other parts of the code presume it is cylindrical. + if (BSParam.AvatarUseBefore09SizeComputation) + { - // Scale is multiplier of radius with one of "0.5" + // Bullet's capsule total height is the "passed height + radius * 2"; + // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) + // The number we pass in for 'scaling' is the multiplier to get that base + // shape to be the size desired. + // So, when creating the scale for the avatar height, we take the passed height + // (size.Z) and remove the caps. + // An oddity of the Bullet capsule implementation is that it presumes the Y + // dimension is the radius of the capsule. Even though some of the code allows + // for a asymmetrical capsule, other parts of the code presume it is cylindrical. - float heightAdjust = BSParam.AvatarHeightMidFudge; - if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) - { - const float AVATAR_LOW = 1.1f; - const float AVATAR_MID = 1.775f; // 1.87f - const float AVATAR_HI = 2.45f; - // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. - float midHeightOffset = size.Z - AVATAR_MID; - if (midHeightOffset < 0f) + // Scale is multiplier of radius with one of "0.5" + + float heightAdjust = BSParam.AvatarHeightMidFudge; + if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) { - // Small avatar. Add the adjustment based on the distance from midheight - heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; + const float AVATAR_LOW = 1.1f; + const float AVATAR_MID = 1.775f; // 1.87f + const float AVATAR_HI = 2.45f; + // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. + float midHeightOffset = size.Z - AVATAR_MID; + if (midHeightOffset < 0f) + { + // Small avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; + } + else + { + // Large avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; + } + } + if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + { + newScale.X = size.X / 2f; + newScale.Y = size.Y / 2f; + // The total scale height is the central cylindar plus the caps on the two ends. + newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; } else { - // Large avatar. Add the adjustment based on the distance from midheight - heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; + newScale.Z = size.Z + heightAdjust; } - } - if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) - { - newScale.X = size.X / 2f; - newScale.Y = size.Y / 2f; - // The total scale height is the central cylindar plus the caps on the two ends. - newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; + // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); + + // If smaller than the endcaps, just fake like we're almost that small + if (newScale.Z < 0) + newScale.Z = 0.1f; + + DetailLog("{0},BSCharacter.ComputeAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", + LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); } else { - newScale.Z = size.Z + heightAdjust; + newScale.Z = size.Z + _footOffset; + DetailLog("{0},BSCharacter.ComputeAvatarScale,using newScale={1}, footOffset={2}", LocalID, newScale, _footOffset); } - // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); - - // If smaller than the endcaps, just fake like we're almost that small - if (newScale.Z < 0) - newScale.Z = 0.1f; - - DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", - LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); return newScale; } @@ -744,17 +786,24 @@ public sealed class BSCharacter : BSPhysObject // set _avatarVolume and _mass based on capsule size, _density and Scale private void ComputeAvatarVolumeAndMass() { - _avatarVolume = (float)( - Math.PI - * Size.X / 2f - * Size.Y / 2f // the area of capsule cylinder - * Size.Z // times height of capsule cylinder - + 1.33333333f - * Math.PI - * Size.X / 2f - * Math.Min(Size.X, Size.Y) / 2 - * Size.Y / 2f // plus the volume of the capsule end caps - ); + if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + { + _avatarVolume = (float)( + Math.PI + * Size.X / 2f + * Size.Y / 2f // the area of capsule cylinder + * Size.Z // times height of capsule cylinder + + 1.33333333f + * Math.PI + * Size.X / 2f + * Math.Min(Size.X, Size.Y) / 2 + * Size.Y / 2f // plus the volume of the capsule end caps + ); + } + else + { + _avatarVolume = Size.X * Size.Y * Size.Z; + } _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; } @@ -773,7 +822,7 @@ public sealed class BSCharacter : BSPhysObject // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many // extra updates. // - // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to + // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. // This is most noticeable in level flight and can be seen with // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower @@ -787,7 +836,7 @@ public sealed class BSCharacter : BSPhysObject RawVelocity = entprop.Velocity; _acceleration = entprop.Acceleration; - _rotationalVelocity = entprop.RotationalVelocity; + RawRotationalVelocity = entprop.RotationalVelocity; // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) @@ -807,7 +856,7 @@ public sealed class BSCharacter : BSPhysObject // PhysScene.PostUpdate(this); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); + LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, RawRotationalVelocity); } } } -- cgit v1.1 From cdb1851f438349a8721c0d9cef54837d0b302189 Mon Sep 17 00:00:00 2001 From: onefang Date: Tue, 4 Jun 2019 00:50:59 +1000 Subject: Warnings-- --- OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs') diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs index d182c34..6b32bf8 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -56,7 +56,7 @@ public sealed class BSCharacter : BSPhysObject private float _buoyancy; private OMV.Vector3 _size; - private float _footOffset; + private float _footOffset = 0; private BSActorAvatarMove m_moveActor; private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; -- cgit v1.1