diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 0de5d4a5ca..d0dd71f224 100755 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -369,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods /// cannot retain a reference to it outside of that method. /// - private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); + private readonly AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 5af6959f0a..9c39eae81c 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -498,18 +498,20 @@ namespace OpenSim.Region.Framework.Scenes.Animation { Falling = false; currentControlState = motionControlStates.landing; - - // TODO: SOFT_LAND support - float fallVsq = m_lastFallVelocity * m_lastFallVelocity; - if (fallVsq > 300f) // aprox 20*h + + if ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM)) == 0) { - m_animTickLand = Environment.TickCount + 3000; - return "STANDUP"; - } - if (fallVsq > 160f) - { - m_animTickLand = Environment.TickCount + 1500; - return "SOFT_LAND"; + float fallVsq = m_lastFallVelocity * m_lastFallVelocity; + if (fallVsq > 300f) // aprox 20*h + { + m_animTickLand = Environment.TickCount + 3000; + return "STANDUP"; + } + if (fallVsq > 160f) + { + m_animTickLand = Environment.TickCount + 1500; + return "SOFT_LAND"; + } } m_animTickLand = Environment.TickCount + 600; return "LAND"; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 292e7a722a..c2ef3ebff5 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2593,15 +2593,12 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", // Scene.Name, remoteClient.Name, (ACFlags)agentData.ControlFlags); - if (IsChildAgent) + if (IsChildAgent || IsInTransit) { //m_log.DebugFormat("DEBUG: HandleAgentUpdate: child agent in {0}", Scene.Name); return; } - if (IsInTransit) - return; - #region Sanity Checking // This is irritating. Really. @@ -2633,62 +2630,48 @@ namespace OpenSim.Region.Framework.Scenes #region Inputs - ACFlags allFlags = (ACFlags)agentData.ControlFlags; - // The Agent's Draw distance setting // When we get to the point of re-computing neighbors everytime this // changes, then start using the agent's drawdistance rather than the // region's draw distance. - DrawDistance = agentData.Far; - m_mouseLook = (allFlags & ACFlags.AGENT_CONTROL_MOUSELOOK) != 0; + ACFlags allFlags = (ACFlags)agentData.ControlFlags; // FIXME: This does not work as intended because the viewer only sends the lbutton down when the button // is first pressed, not whilst it is held down. If this is required in the future then need to look // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not // received (e.g. on holding LMB down on the avatar in a viewer). m_leftButtonDown = (allFlags & ACFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; + m_mouseLook = (allFlags & ACFlags.AGENT_CONTROL_MOUSELOOK) != 0; + m_headrotation = agentData.HeadRotation; + + bool hadState = State != 0; + State = agentData.State; #endregion Inputs - // Make anims work for client side autopilot - //if ((flags & ACFlags.AGENT_CONTROL_AT_POS) != 0) - // m_updateCount = UPDATE_COUNT; - - // Make turning in place work - //if ((flags & ACFlags.AGENT_CONTROL_YAW_POS) != 0 || - // (flags & ACFlags.AGENT_CONTROL_YAW_NEG) != 0) - // m_updateCount = UPDATE_COUNT; - + if (hadState || State != 0) + SendAgentTerseUpdate(this); if ((allFlags & ACFlags.AGENT_CONTROL_STAND_UP) != 0) - { StandUp(); - } + + if ((allFlags & ACFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) + HandleAgentSitOnGround(); + + ACFlags flags = RemoveIgnoredControls(allFlags, IgnoredControls); + m_AgentControlFlags = flags; + + if (AllowMovement) + Rotation = agentData.BodyRotation; // Raycast from the avatar's head to the camera to see if there's anything blocking the view // this exclude checks may not be complete - if(agentData.NeedsCameraCollision) // condition parentID may be wrong + if (agentData.NeedsCameraCollision) checkCameraCollision(); - ACFlags flags = RemoveIgnoredControls(allFlags, IgnoredControls); - - if ((flags & ACFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) - HandleAgentSitOnGround(); - - // In the future, these values might need to go global. - // Here's where you get them. - m_AgentControlFlags = flags; - m_headrotation = agentData.HeadRotation; - byte oldState = State; - State = agentData.State; - - // We need to send this back to the client in order to stop the edit beams - if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None) - SendAgentTerseUpdate(this); - - PhysicsActor actor = PhysicsActor; + PhysicsActor actor = m_physActor; // This will be the case if the agent is sitting on the groudn or on an object. if (actor == null) @@ -2697,17 +2680,12 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (AllowMovement && !SitGround) + if (AllowMovement) { -// m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); - bool update_rotation = false; - if (!IsSatOnObject && agentData.BodyRotation != Rotation) - { - Rotation = agentData.BodyRotation; - update_rotation = true; - } - + //m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); bool update_movementflag = false; + bool DCFlagKeyPressed = false; + bool mvToTarget = m_movingToTarget; if (agentData.UseClientAgentPosition) { @@ -2716,149 +2694,116 @@ namespace OpenSim.Region.Framework.Scenes m_moveToSpeed = -1f; } - int i = 0; - bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; float agent_velocity = AgentControlNormalVel; - bool newFlying = false; + bool bAllowUpdateMoveToPosition = false; + uint currflags = (uint)flags & (CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); + uint oldflags = MovementFlag & (CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); + MovementFlag &= ~(CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); + if (currflags != 0) + { + DCFlagKeyPressed = true; + mvToTarget = false; + + MovementFlag |= currflags; + //update_movementflag |= (currflags ^ oldflags) != 0; + update_movementflag = true; + + if ((currflags & CONTROL_FLAG_NUDGE_MASK) != 0) + { + currflags >>= 19; + if(m_delayedStop < 0) + agent_velocity = AgentControlNudgeVel; + } + + for (int i = 0, mask = 1; i < 6; ++i, mask <<= 1) + { + if((currflags & mask) != 0) + agent_control_v3 += Dir_Vectors[i]; + } + } + else + { + if(oldflags == 0) + bAllowUpdateMoveToPosition = true; + else + update_movementflag = true; + } + + bool newFlying; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; - else if(mvToTarget) + else if (mvToTarget) newFlying = actor.Flying; else newFlying = ((flags & ACFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != newFlying) { - // Note: ScenePresence.Flying is actually fetched from the physical actor - // so setting PhysActor.Flying here also sets the ScenePresence's value. actor.Flying = newFlying; update_movementflag = true; } - if (ParentID == 0) + // Detect AGENT_CONTROL_STOP state changes + if (AgentControlStopActive != ((flags & ACFlags.AGENT_CONTROL_STOP) != 0)) { - bool bAllowUpdateMoveToPosition = false; - uint currflags = (uint)flags & (CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); - uint oldflags = MovementFlag & (CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); - MovementFlag &= ~(CONTROL_FLAG_NUDGE_MASK | CONTROL_FLAG_NORM_MASK); - - if (currflags != 0) - { - DCFlagKeyPressed = true; - MovementFlag |= currflags; - //update_movementflag |= (currflags ^ oldflags) != 0; - update_movementflag = true; - - if ((currflags & CONTROL_FLAG_NUDGE_MASK) != 0) - { - currflags >>= 19; - if(m_delayedStop < 0) - agent_velocity = AgentControlNudgeVel; - } - - uint mask = 1; - for (i= 0; i < 6; ++i, mask <<= 1) - { - if((currflags & mask) != 0) - agent_control_v3 += Dir_Vectors[i]; - } - } - else - { - if(oldflags == 0) - bAllowUpdateMoveToPosition = true; - else - update_movementflag = true; - } - - // Detect AGENT_CONTROL_STOP state changes - if (AgentControlStopActive != ((flags & ACFlags.AGENT_CONTROL_STOP) != 0)) - { - AgentControlStopActive = !AgentControlStopActive; - update_movementflag = true; - } - - if (m_movingToTarget) - { - // If the user has pressed a key then we want to cancel any move to target. - if (DCFlagKeyPressed) - { - ResetMoveToTarget(); - update_movementflag = true; - } - else if (bAllowUpdateMoveToPosition) - { - // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a - // certain position. It's only check for tolerance on returning to that position is 0.2 - // rather than 1, at which point it removes its force target. - if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2f : 0.5f, ref agent_control_v3)) - update_movementflag = true; - } - } + AgentControlStopActive = !AgentControlStopActive; + update_movementflag = true; } - // Cause the avatar to stop flying if it's colliding - // with something with the down arrow pressed. + if (m_movingToTarget) + { + // If the user has pressed a key then we want to cancel any move to target. + if (DCFlagKeyPressed) + { + ResetMoveToTarget(); + update_movementflag = true; + } + else if (bAllowUpdateMoveToPosition) + { + // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a + // certain position. It's only check for tolerance on returning to that position is 0.2 + // rather than 1, at which point it removes its force target. + if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2f : 0.5f, ref agent_control_v3)) + update_movementflag = true; + } + } // Only do this if we're flying if (Flying && !ForceFly) { - // Need to stop in mid air if user holds down AGENT_CONTROL_STOP - //if (AgentControlStopActive) - //{ - // agent_control_v3 = Vector3.Zero; - //} - //else + //m_log.Debug("[CONTROL]: " +flags); + // Applies a satisfying roll effect to the avatar when flying. + const ACFlags flagsLeft = ACFlags.AGENT_CONTROL_TURN_LEFT | ACFlags.AGENT_CONTROL_YAW_POS; + const ACFlags flagsRight = ACFlags.AGENT_CONTROL_TURN_RIGHT | ACFlags.AGENT_CONTROL_YAW_NEG; + if ((flags & flagsLeft) == flagsLeft) { - // Landing detection code - // Are the landing controls requirements filled? - //bool controlland = (flags & (ACFlags.AGENT_CONTROL_UP_NEG | ACFlags.AGENT_CONTROL_NUDGE_UP_NEG)) != 0; - - //m_log.Debug("[CONTROL]: " +flags); - // Applies a satisfying roll effect to the avatar when flying. - const ACFlags flagsLeft = ACFlags.AGENT_CONTROL_TURN_LEFT | ACFlags.AGENT_CONTROL_YAW_POS; - const ACFlags flagsRight = ACFlags.AGENT_CONTROL_TURN_RIGHT | ACFlags.AGENT_CONTROL_YAW_NEG; - if ((flags & flagsLeft) == flagsLeft) - { - ApplyFlyingRoll( - FLY_ROLL_RADIANS_PER_UPDATE, - (flags & ACFlags.AGENT_CONTROL_UP_POS) != 0, - (flags & ACFlags.AGENT_CONTROL_UP_NEG) != 0); - } - else if ((flags & flagsRight) == flagsRight) - { - ApplyFlyingRoll( - -FLY_ROLL_RADIANS_PER_UPDATE, - (flags & ACFlags.AGENT_CONTROL_UP_POS) != 0, - (flags & ACFlags.AGENT_CONTROL_UP_NEG) != 0); - } - else - { - if (m_AngularVelocity.Z != 0) - m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); - } - - /* - if (Flying && IsColliding && controlland) - { - // nesting this check because LengthSquared() is expensive and we don't - // want to do it every step when flying. - if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) - StopFlying(); - } - */ + ApplyFlyingRoll( + FLY_ROLL_RADIANS_PER_UPDATE, + (flags & ACFlags.AGENT_CONTROL_UP_POS) != 0, + (flags & ACFlags.AGENT_CONTROL_UP_NEG) != 0); + } + else if ((flags & flagsRight) == flagsRight) + { + ApplyFlyingRoll( + -FLY_ROLL_RADIANS_PER_UPDATE, + (flags & ACFlags.AGENT_CONTROL_UP_POS) != 0, + (flags & ACFlags.AGENT_CONTROL_UP_NEG) != 0); + } + else + { + if (m_AngularVelocity.Z != 0) + m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); } } else if (IsColliding && agent_control_v3.Z < 0f) agent_control_v3.Z = 0; -// else if(AgentControlStopActive %% Velocity.Z <0.01f) -// m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); + //m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop @@ -2867,12 +2812,11 @@ namespace OpenSim.Region.Framework.Scenes // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the // avatar location in place). - if (update_movementflag - || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0))) + if (update_movementflag) { if (AgentControlStopActive) { - // if (MovementFlag == 0 && Animator.Falling) + //if (MovementFlag == 0 && Animator.Falling) if (MovementFlag == 0 && Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling) { AddNewMovement(agent_control_v3, AgentControlStopSlowVel, true); @@ -2896,23 +2840,10 @@ namespace OpenSim.Region.Framework.Scenes } } } - else if((flags & ACFlags.AGENT_CONTROL_FINISH_ANIM) != 0) + else Animator.UpdateMovementAnimations(); - /* - if (update_movementflag && ParentID == 0 && m_delayedStop < 0) - { - //m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name); - Animator.UpdateMovementAnimations(); - } - */ SendControlsToScripts((uint)allFlags); } - - // We need to send this back to the client in order to see the edit beams - if ((State & (uint)AgentState.Editing) != 0) - SendAgentTerseUpdate(this); - -// m_scene.EventManager.TriggerOnClientMovement(this); } private void HandleAgentFOV(IClientAPI remoteClient, float _fov) diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 3d51a634c5..c18056d0ac 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -113,7 +113,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; - moveArgs.SessionID = acd.SessionID; originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); @@ -209,7 +208,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; - moveArgs.SessionID = acd.SessionID; originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs index d87539f45e..2c42b046eb 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs @@ -83,6 +83,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde private Quaternion m_orientation; private Quaternion m_orientation2D; private float m_mass = 80f; + private float m_massInvTimeScaled = 1600f; public readonly float m_density = 60f; private bool m_pidControllerActive = true; @@ -94,7 +95,8 @@ namespace OpenSim.Region.PhysicsModule.ubOde public float PID_P; private readonly ODEScene m_parent_scene; - private readonly float m_scenegravityZ; + private readonly float m_sceneGravityZ; + private float m_scenegravityForceZ; private readonly float m_sceneTimeStep; private readonly float m_sceneInverseTimeStep; @@ -166,7 +168,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde m_localID = localID; m_parent_scene = parent_scene; - m_scenegravityZ = parent_scene.gravityz; + m_sceneGravityZ = parent_scene.gravityz; m_sceneTimeStep = parent_scene.ODE_STEPSIZE; m_sceneInverseTimeStep = 1.0f / m_sceneTimeStep; @@ -206,10 +208,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde m_runMultiplier = 1.0f / rundivisor; m_mass = m_density * m_size.X * m_size.Y * m_size.Z; - ; // sure we have a default + m_massInvTimeScaled = m_mass * m_sceneInverseTimeStep; + // sure we have a default - PID_D = basePID_D * m_mass * m_sceneInverseTimeStep; - PID_P = basePID_P * m_mass * m_sceneInverseTimeStep; + PID_D = basePID_D * m_massInvTimeScaled; + PID_P = basePID_P * m_massInvTimeScaled; + + m_scenegravityForceZ = m_sceneGravityZ * m_mass; m_isPhysical = false; // current status: no ODE information exists @@ -792,7 +797,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (pushforce) { - AddChange(changes.Force, force * m_density / (m_sceneTimeStep * 28f)); + AddChange(changes.Force, force * m_density * m_sceneInverseTimeStep / 28f); } else { @@ -809,7 +814,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde public override void AvatarJump(float impulseZ) { // convert back to force and remove mass effect - AddChange(changes.Force, new Vector3(0, 0, impulseZ * m_sceneInverseTimeStep * m_mass)); + AddChange(changes.Force, new Vector3(0, 0, impulseZ * m_massInvTimeScaled)); } public override void AddAngularForce(Vector3 force, bool pushforce) @@ -858,11 +863,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde capsule = SafeNativeMethods.CreateCapsule(collider, r, l); - m_mass = m_density * sx * sy * sz; // update mass + // update mass + m_mass = m_density * sx * sy * sz; SafeNativeMethods.MassSetBoxTotal(out ShellMass, m_mass, sx, sy, sz); - - PID_D = basePID_D * m_mass * m_sceneInverseTimeStep; - PID_P = basePID_P * m_mass * m_sceneInverseTimeStep; + m_massInvTimeScaled = m_mass * m_sceneInverseTimeStep; + PID_D = basePID_D * m_massInvTimeScaled; + PID_P = basePID_P * m_massInvTimeScaled; + m_scenegravityForceZ = m_sceneGravityZ * m_mass; Body = SafeNativeMethods.BodyCreate(m_parent_scene.world); @@ -1437,7 +1444,8 @@ namespace OpenSim.Region.PhysicsModule.ubOde vec.Y += (ctz.Y - vel.Y) * pidd0833; // hack for breaking on fall if (ctz.Z == -9999f) - vec.Z += -vel.Z * PID_D - m_scenegravityZ * m_mass; + vec.Z += -vel.Z * PID_D - m_scenegravityForceZ; + ; } } else @@ -1515,7 +1523,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde vec.Y += (ctz.Y - vel.Y) * pidd0833; // hack for breaking on fall if (ctz.Z == -9999f) - vec.Z += -vel.Z * PID_D - m_scenegravityZ * m_mass; + vec.Z += -vel.Z * PID_D - m_scenegravityForceZ; } } } @@ -1541,7 +1549,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde if (m_flying || hoverPIDActive) { - vec.Z -= m_scenegravityZ * m_mass; + vec.Z -= m_sceneGravityZ * m_mass; if (!hoverPIDActive) { @@ -1557,7 +1565,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde } else if (m_buoyancy != 0.0) { - vec.Z -= m_scenegravityZ * m_buoyancy * m_mass; + vec.Z -= m_scenegravityForceZ * m_buoyancy; } if (vec.IsFinite()) @@ -1880,11 +1888,14 @@ namespace OpenSim.Region.PhysicsModule.ubOde SafeNativeMethods.GeomCapsuleSetParams(capsule, r, l); m_mass = m_density * sx * sy * sz; // update mass - PID_D = basePID_D * m_mass * m_sceneInverseTimeStep; - PID_P = basePID_P * m_mass * m_sceneInverseTimeStep; + m_massInvTimeScaled = m_mass * m_sceneInverseTimeStep; + PID_D = basePID_D * m_massInvTimeScaled; + PID_P = basePID_P * m_massInvTimeScaled; SafeNativeMethods.MassSetBoxTotal(out ShellMass, m_mass, sx, sy, sz); SafeNativeMethods.BodySetMass(Body, ref ShellMass); + m_scenegravityForceZ = m_sceneGravityZ * m_mass; + _position.Z += (sz - oldsz) * 0.5f; SafeNativeMethods.BodySetPosition(Body, _position.X, _position.Y, _position.Z);