示例#1
0
        public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt)
        {
            IBlockAccessor blockAccess = entity.World.BlockAccessor;
            float          dtFac       = 60 * dt;

            moveDelta.Set(pos.Motion.X * dtFac, pos.Motion.Y * dtFac, pos.Motion.Z * dtFac);

            nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z);
            bool falling            = pos.Motion.Y < 0;
            bool feetInLiquidBefore = entity.FeetInLiquid;
            bool onGroundBefore     = entity.OnGround;
            bool swimmingBefore     = entity.Swimming;

            double prevYMotion = pos.Motion.Y;

            controls.IsClimbing = false;

            if (!onGroundBefore && entity.Properties.CanClimb == true)
            {
                int height = (int)Math.Ceiling(entity.CollisionBox.Y2);

                entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z);

                for (int dy = 0; dy < height; dy++)
                {
                    tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z);
                    Block nblock = blockAccess.GetBlock(tmpPos);
                    if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                    {
                        continue;
                    }

                    Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                    if (collBoxes == null)
                    {
                        continue;
                    }

                    for (int i = 0; i < collBoxes.Length; i++)
                    {
                        double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos);
                        controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                        if (controls.IsClimbing)
                        {
                            entity.ClimbingOnFace = null;
                            break;
                        }
                    }
                }

                for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++)
                {
                    BlockFacing facing = BlockFacing.HORIZONTALS[i];
                    for (int dy = 0; dy < height; dy++)
                    {
                        tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z);
                        Block nblock = blockAccess.GetBlock(tmpPos);
                        if (!nblock.Climbable && !(entity.Properties.CanClimbAnywhere && entity.Alive))
                        {
                            continue;
                        }

                        Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                        if (collBoxes == null)
                        {
                            continue;
                        }

                        for (int j = 0; j < collBoxes.Length; j++)
                        {
                            double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos);
                            controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                            if (controls.IsClimbing)
                            {
                                entity.ClimbingOnFace    = facing;
                                entity.ClimbingOnCollBox = collBoxes[j];
                                break;
                            }
                        }
                    }
                }
            }


            if (controls.IsClimbing)
            {
                if (controls.WalkVector.Y == 0)
                {
                    pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y;
                    if (controls.Jump)
                    {
                        pos.Motion.Y = 0.035 * dt * 60f;
                    }
                }

                // what was this for? it causes jitter
                //moveDelta.Y = pos.Motion.Y * dt * 60f;
                //nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z);
            }

            collisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition, stepHeight);

            if (!entity.Properties.CanClimbAnywhere)
            {
                controls.IsStepping = HandleSteppingOnBlocks(pos, moveDelta, dtFac, controls);
            }

            HandleSneaking(pos, controls, dt);

            if (entity.CollidedHorizontally && !controls.IsClimbing && !controls.IsStepping)
            {
                if (blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z).LiquidLevel >= 7 || (blockAccess.GetBlock((int)pos.X, (int)(pos.Y - 0.05), (int)pos.Z).LiquidLevel >= 7))
                {
                    pos.Motion.Y       += 0.2 * dt;
                    controls.IsStepping = true;
                }
            }


            if (blockAccess.IsNotTraversable((pos.X + pos.Motion.X * dt * 60f), pos.Y, pos.Z))
            {
                outposition.X = pos.X;
            }
            if (blockAccess.IsNotTraversable(pos.X, (pos.Y + pos.Motion.Y * dt * 60f), pos.Z))
            {
                outposition.Y = pos.Y;
            }
            if (blockAccess.IsNotTraversable(pos.X, pos.Y, (pos.Z + pos.Motion.Z * dt * 60f)))
            {
                outposition.Z = pos.Z;
            }

            pos.SetPos(outposition);


            // Set the motion to zero if he collided.

            if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0))
            {
                pos.Motion.X = 0;
            }

            if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0))
            {
                pos.Motion.Y = 0;
            }

            if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0))
            {
                pos.Motion.Z = 0;
            }

            float offX = entity.CollisionBox.X2 - entity.OriginCollisionBox.X2;
            float offZ = entity.CollisionBox.Z2 - entity.OriginCollisionBox.Z2;

            int posX = (int)(pos.X + offX);
            int posZ = (int)(pos.Z + offZ);

            Block block       = blockAccess.GetBlock(posX, (int)(pos.Y), posZ);
            Block aboveblock  = blockAccess.GetBlock(posX, (int)(pos.Y + 1), posZ);
            Block middleBlock = blockAccess.GetBlock(posX, (int)(pos.Y + entity.SwimmingOffsetY), posZ);


            entity.OnGround     = (entity.CollidedVertically && falling && !controls.IsClimbing) || controls.IsStepping;
            entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y);
            entity.InLava       = block.LiquidCode == "lava";
            entity.Swimming     = middleBlock.IsLiquid();

            if (!onGroundBefore && entity.OnGround)
            {
                entity.OnFallToGround(prevYMotion);
            }

            if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming))
            {
                entity.OnCollideWithLiquid();
            }

            if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming))
            {
                entity.OnExitedLiquid();
            }

            if (!falling || entity.OnGround || controls.IsClimbing)
            {
                entity.PositionBeforeFalling.Set(outposition);
            }

            Cuboidd testedEntityBox = collisionTester.entityBox;

            for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++)
            {
                for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++)
                {
                    for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++)
                    {
                        collisionTester.tmpPos.Set(x, y, z);
                        collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1);

                        if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox))
                        {
                            // Saves us a few cpu cycles
                            if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z)
                            {
                                block.OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                                continue;
                            }

                            blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Performs the physics on the specified entity.
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="pos"></param>
        public void DoPhysics(float dt, EntityPos pos)
        {
            Vec3d motionBefore       = pos.Motion.Clone();
            bool  feetInLiquidBefore = entity.FeetInLiquid;
            bool  onGroundBefore     = entity.OnGround;
            bool  swimmingBefore     = entity.Swimming;
            bool  onCollidedBefore   = entity.Collided;

            float dtFac = 60 * dt;

            Block belowBlock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y - 0.05f), (int)pos.Z);

            // On ground drag
            if (entity.OnGround)
            {
                if (!entity.FeetInLiquid)
                {
                    pos.Motion.X *= (1 - groundDragFactor * belowBlock.DragMultiplier);
                    pos.Motion.Z *= (1 - groundDragFactor * belowBlock.DragMultiplier);
                }
            }

            // Water or air drag
            if (entity.FeetInLiquid || entity.Swimming)
            {
                pos.Motion *= (float)Math.Pow(waterDragValue, dt * 33);
            }
            else
            {
                pos.Motion *= (float)Math.Pow(airDragValue, dt * 33);
            }

            Block inblock    = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z);
            Block aboveblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z);

            if (entity.FeetInLiquid)
            {
                Vec3d pushvec = inblock.PushVector;
                if (pushvec != null)
                {
                    float pushstrength = 0.3f * 1000f / GameMath.Clamp(entity.MaterialDensity, 750, 2500) * dtFac;

                    pos.Motion.Add(
                        pushvec.X * pushstrength,
                        pushvec.Y * pushstrength,
                        pushvec.Z * pushstrength
                        );
                }
            }


            // Gravity
            if (pos.Y > -100 && entity.ApplyGravity)
            {
                double gravStrength = gravityPerSecond / 60f * dtFac + Math.Max(0, -0.015f * pos.Motion.Y * dtFac);

                if (entity.Swimming)
                {
                    // above 0 => floats
                    // below 0 => sinks
                    float baseboyancy = GameMath.Clamp(1 - entity.MaterialDensity / inblock.MaterialDensity, -1, 1);

                    float waterY = (int)pos.Y + inblock.LiquidLevel / 8f + (aboveblock.IsLiquid() ? 9 / 8f : 0);

                    float bottomSubmergedness = waterY - (float)pos.Y;

                    // 0 = at swim line
                    // 1 = completely submerged
                    float swimlineSubmergedness = GameMath.Clamp(bottomSubmergedness - (entity.SelectionBox.Y2 - (float)entity.SwimmingOffsetY), 0, 1);

                    double boyancyStrength = GameMath.Clamp(60 * baseboyancy * swimlineSubmergedness, -1.5f, 1.5f) - 1;

                    double waterDrag = GameMath.Clamp(100 * Math.Abs(pos.Motion.Y * dtFac) - 0.02f, 1, 1.25f);

                    pos.Motion.Y += gravStrength * boyancyStrength;
                    pos.Motion.Y /= waterDrag;
                }
                else
                {
                    pos.Motion.Y -= gravStrength;
                }
            }


            moveDelta.Set(pos.Motion.X * dtFac, pos.Motion.Y * dtFac, pos.Motion.Z * dtFac);
            nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z);


            bool falling = pos.Motion.Y < 0;

            entity.World.CollisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition, 0, collisionYExtra);



            if (entity.World.BlockAccessor.IsNotTraversable((int)(pos.X + moveDelta.X), (int)pos.Y, (int)pos.Z))
            {
                outposition.X = pos.X;
            }
            if (entity.World.BlockAccessor.IsNotTraversable((int)pos.X, (int)(pos.Y + moveDelta.Y), (int)pos.Z))
            {
                outposition.Y = pos.Y;
            }
            if (entity.World.BlockAccessor.IsNotTraversable((int)pos.X, (int)pos.Y, (int)(pos.Z + moveDelta.Z)))
            {
                outposition.Z = pos.Z;
            }

            entity.OnGround = entity.CollidedVertically && falling;
            pos.SetPos(outposition);


            if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0))
            {
                pos.Motion.X = 0;
            }

            if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0))
            {
                pos.Motion.Y = 0;
            }

            if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0))
            {
                pos.Motion.Z = 0;
            }



            Block block = entity.World.BlockAccessor.GetBlock(pos.XInt, pos.YInt, pos.ZInt);

            entity.FeetInLiquid = block.MatterState == EnumMatterState.Liquid;
            entity.InLava       = block.LiquidCode == "lava";
            if (entity.FeetInLiquid)
            {
                float waterY = (int)pos.Y + block.LiquidLevel / 8f + (aboveblock.IsLiquid() ? 9 / 8f : 0);
                float bottomSubmergedness = waterY - (float)pos.Y;

                // 0 = at swim line
                // 1 = completely submerged
                float swimlineSubmergedness = bottomSubmergedness - (entity.SelectionBox.Y2 - (float)entity.SwimmingOffsetY);

                entity.Swimming = swimlineSubmergedness > 0;
            }
            else
            {
                entity.Swimming = false;
            }

            if (!onCollidedBefore && entity.Collided)
            {
                entity.OnCollided();
            }

            if (!onGroundBefore && entity.OnGround)
            {
                entity.OnFallToGround(motionBefore.Y);
            }
            if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming))
            {
                entity.OnCollideWithLiquid();
            }
            if (!falling || entity.OnGround)
            {
                entity.PositionBeforeFalling.Set(outposition);
            }

            if (GlobalConstants.OutsideWorld(pos.X, pos.Y, pos.Z, entity.World.BlockAccessor))
            {
                entity.DespawnReason = new EntityDespawnReason()
                {
                    reason = EnumDespawnReason.Death, damageSourceForDeath = new DamageSource()
                    {
                        Source = EnumDamageSource.Fall
                    }
                };
                return;
            }

            Cuboidd entityBox = entity.World.CollisionTester.entityBox;

            for (int y = (int)entityBox.Y1; y <= (int)entityBox.Y2; y++)
            {
                for (int x = (int)entityBox.X1; x <= (int)entityBox.X2; x++)
                {
                    for (int z = (int)entityBox.Z1; z <= (int)entityBox.Z2; z++)
                    {
                        entity.World.CollisionTester.tmpPos.Set(x, y, z);
                        entity.World.CollisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1);
                        if (entity.World.CollisionTester.tempCuboid.IntersectsOrTouches(entityBox))
                        {
                            entity.World.BlockAccessor.GetBlock(x, y, z).OnEntityInside(entity.World, entity, entity.World.CollisionTester.tmpPos);
                        }
                    }
                }
            }

            OnPhysicsTickCallback?.Invoke(dtFac);
        }
示例#3
0
        public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt)
        {
            IBlockAccessor blockAccess = entity.World.BlockAccessor;

            nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z);
            bool falling            = pos.Motion.Y < 0;
            bool feetInLiquidBefore = entity.FeetInLiquid;
            bool onGroundBefore     = entity.OnGround;
            bool swimmingBefore     = entity.Swimming;

            double prevYMotion = pos.Motion.Y;

            controls.IsClimbing = false;

            if (!onGroundBefore && entity.Properties.CanClimb == true)
            {
                int height = (int)Math.Ceiling(entity.CollisionBox.Y2);

                entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z);

                for (int dy = 0; dy < height; dy++)
                {
                    tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z);
                    Block nblock = blockAccess.GetBlock(tmpPos);
                    if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                    {
                        continue;
                    }

                    Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                    if (collBoxes == null)
                    {
                        continue;
                    }

                    for (int i = 0; i < collBoxes.Length; i++)
                    {
                        double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos);
                        controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                        if (controls.IsClimbing)
                        {
                            entity.ClimbingOnFace = null;
                            break;
                        }
                    }
                }

                for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++)
                {
                    BlockFacing facing = BlockFacing.HORIZONTALS[i];
                    for (int dy = 0; dy < height; dy++)
                    {
                        tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z);
                        Block nblock = blockAccess.GetBlock(tmpPos);
                        if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                        {
                            continue;
                        }

                        Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                        if (collBoxes == null)
                        {
                            continue;
                        }

                        for (int j = 0; j < collBoxes.Length; j++)
                        {
                            double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos);
                            controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                            if (controls.IsClimbing)
                            {
                                entity.ClimbingOnFace = facing;
                                break;
                            }
                        }
                    }
                }
            }


            if (controls.IsClimbing)
            {
                if (controls.WalkVector.Y == 0)
                {
                    pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y;
                    if (controls.Jump)
                    {
                        pos.Motion.Y = 0.04;
                    }
                }

                nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z);
            }

            collisionTester.ApplyTerrainCollision(entity, pos, ref outposition, !(entity is EntityPlayer));

            bool isStepping = HandleSteppingOnBlocks(pos, controls);

            HandleSneaking(pos, controls, dt);



            if (blockAccess.IsNotTraversable((int)(pos.X + pos.Motion.X), (int)pos.Y, (int)pos.Z))
            {
                outposition.X = pos.X;
            }
            if (blockAccess.IsNotTraversable((int)pos.X, (int)(pos.Y + pos.Motion.Y), (int)pos.Z))
            {
                outposition.Y = pos.Y;
            }
            if (blockAccess.IsNotTraversable((int)pos.X, (int)pos.Y, (int)(pos.Z + pos.Motion.Z)))
            {
                outposition.Z = pos.Z;
            }

            pos.SetPos(outposition);


            // Set the players motion to zero if he collided.

            if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0))
            {
                pos.Motion.X = 0;
            }

            if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0))
            {
                pos.Motion.Y = 0;
            }

            if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0))
            {
                pos.Motion.Z = 0;
            }



            Block block       = blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z);
            Block aboveblock  = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z);
            Block middleBlock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + entity.CollisionBox.Y1 + entity.CollisionBox.Y2 * 0.66f), (int)pos.Z);


            entity.OnGround     = (entity.CollidedVertically && falling && !controls.IsClimbing) || isStepping;
            entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y);
            entity.Swimming     = middleBlock.IsLiquid();
            //    Console.WriteLine(entity.World.Side + ": "+ entity.OnGround + " / " + pos.Y);

            if (!onGroundBefore && entity.OnGround)
            {
                entity.OnFallToGround(prevYMotion);
            }

            if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming))
            {
                entity.OnCollideWithLiquid();
            }

            if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming))
            {
                entity.OnExitedLiquid();
            }

            if (!falling || entity.OnGround || controls.IsClimbing)
            {
                entity.PositionBeforeFalling.Set(outposition);
            }

            Cuboidd testedEntityBox = collisionTester.entityBox;

            for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++)
            {
                for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++)
                {
                    for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++)
                    {
                        collisionTester.tmpPos.Set(x, y, z);
                        collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1);

                        if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox))
                        {
                            // Saves us a few cpu cycles
                            if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z)
                            {
                                block.OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                                continue;
                            }

                            blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                        }
                    }
                }
            }
        }
示例#4
0
        public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt)
        {
            IBlockAccessor    blockAccess = entity.World.BlockAccessor;
            FrameProfilerUtil profiler    = entity.World.FrameProfiler;
            float             dtFac       = 60 * dt;
            double            prevYMotion = pos.Motion.Y;

            moveDelta.Set(pos.Motion.X * dtFac, prevYMotion * dtFac, pos.Motion.Z * dtFac);

            nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z);
            bool falling            = prevYMotion < 0;
            bool feetInLiquidBefore = entity.FeetInLiquid;
            bool onGroundBefore     = entity.OnGround;
            bool swimmingBefore     = entity.Swimming;

            controls.IsClimbing     = false;
            entity.ClimbingOnFace   = null;
            entity.ClimbingIntoFace = null;


            if (/*!onGroundBefore &&*/ entity.Properties.CanClimb == true)
            {
                int height = (int)Math.Ceiling(entity.CollisionBox.Y2);

                entityBox.SetAndTranslate(entity.CollisionBox, pos.X, pos.Y, pos.Z);

                for (int dy = 0; dy < height; dy++)
                {
                    tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z);
                    Block nblock = blockAccess.GetBlock(tmpPos);
                    if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                    {
                        continue;
                    }

                    Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                    if (collBoxes == null)
                    {
                        continue;
                    }

                    for (int i = 0; i < collBoxes.Length; i++)
                    {
                        double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos);
                        controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                        if (controls.IsClimbing)
                        {
                            entity.ClimbingOnFace = null;
                            break;
                        }
                    }
                }

                if (controls.WalkVector.LengthSq() > 0.00001 && entity.Properties.CanClimbAnywhere && entity.Alive)
                {
                    var walkIntoFace = BlockFacing.FromVector(controls.WalkVector.X, controls.WalkVector.Y, controls.WalkVector.Z);
                    if (walkIntoFace != null)
                    {
                        tmpPos.Set((int)pos.X + walkIntoFace.Normali.X, (int)pos.Y + walkIntoFace.Normali.Y, (int)pos.Z + walkIntoFace.Normali.Z);
                        Block nblock = blockAccess.GetBlock(tmpPos);

                        Cuboidf[] icollBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                        entity.ClimbingIntoFace = (icollBoxes != null && icollBoxes.Length != 0) ? walkIntoFace : null;
                    }
                }

                for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++)
                {
                    BlockFacing facing = BlockFacing.HORIZONTALS[i];
                    for (int dy = 0; dy < height; dy++)
                    {
                        tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z);
                        Block nblock = blockAccess.GetBlock(tmpPos);
                        if (!nblock.Climbable && !(entity.Properties.CanClimbAnywhere && entity.Alive))
                        {
                            continue;
                        }

                        Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                        if (collBoxes == null)
                        {
                            continue;
                        }

                        for (int j = 0; j < collBoxes.Length; j++)
                        {
                            double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos);
                            controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                            if (controls.IsClimbing)
                            {
                                entity.ClimbingOnFace    = facing;
                                entity.ClimbingOnCollBox = collBoxes[j];
                                break;
                            }
                        }
                    }
                }
            }


            if (controls.IsClimbing)
            {
                if (controls.WalkVector.Y == 0)
                {
                    pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y;
                    if (controls.Jump)
                    {
                        pos.Motion.Y = 0.035 * dt * 60f;
                    }
                }


                // what was this for? it causes jitter
                // moveDelta.Y = pos.Motion.Y * dt * 60f;
                // nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z);
            }

            profiler.Mark("prep");

            collisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition, stepHeight);

            profiler.Mark("terraincollision");

            if (!entity.Properties.CanClimbAnywhere)
            {
                if (smoothStepping)
                {
                    controls.IsStepping = HandleSteppingOnBlocksSmooth(pos, moveDelta, dtFac, controls);
                }
                else
                {
                    controls.IsStepping = HandleSteppingOnBlocks(pos, moveDelta, dtFac, controls);
                }
            }

            profiler.Mark("stepping-checks");

            HandleSneaking(pos, controls, dt);

            if (entity.CollidedHorizontally && !controls.IsClimbing && !controls.IsStepping && entity.Properties.Habitat != EnumHabitat.Underwater)
            {
                if (blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 0.5), (int)pos.Z).LiquidLevel >= 7 || blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z).LiquidLevel >= 7 || (blockAccess.GetBlock((int)pos.X, (int)(pos.Y - 0.05), (int)pos.Z).LiquidLevel >= 7))
                {
                    pos.Motion.Y       += 0.2 * dt;
                    controls.IsStepping = true;
                }
                else   // attempt to prevent endless collisions
                {
                    double absX = Math.Abs(pos.Motion.X);
                    double absZ = Math.Abs(pos.Motion.Z);
                    if (absX > absZ)
                    {
                        if (absZ < 0.001)
                        {
                            pos.Motion.Z += pos.Motion.Z < 0 ? -0.0025 : 0.0025;
                        }
                    }
                    else
                    {
                        if (absX < 0.001)
                        {
                            pos.Motion.X += pos.Motion.X < 0 ? -0.0025 : 0.0025;
                        }
                    }
                }
            }


            if (outposition.X != pos.X && blockAccess.IsNotTraversable((pos.X + pos.Motion.X * dt * 60f), pos.Y, pos.Z))
            {
                outposition.X = pos.X;
            }
            if (outposition.Y != pos.Y && blockAccess.IsNotTraversable(pos.X, (pos.Y + pos.Motion.Y * dt * 60f), pos.Z))
            {
                outposition.Y = pos.Y;
            }
            if (outposition.Z != pos.Z && blockAccess.IsNotTraversable(pos.X, pos.Y, (pos.Z + pos.Motion.Z * dt * 60f)))
            {
                outposition.Z = pos.Z;
            }

            pos.SetPos(outposition);

            profiler.Mark("apply-motion");

            // Set the motion to zero if he collided.

            if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0))
            {
                pos.Motion.X = 0;
            }

            if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0))
            {
                pos.Motion.Y = 0;
            }

            if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0))
            {
                pos.Motion.Z = 0;
            }

            float offX = entity.CollisionBox.X2 - entity.OriginCollisionBox.X2;
            float offZ = entity.CollisionBox.Z2 - entity.OriginCollisionBox.Z2;

            int posX = (int)(pos.X + offX);
            int posZ = (int)(pos.Z + offZ);

            Block block          = blockAccess.GetBlock(posX, (int)(pos.Y), posZ);
            Block waterOrIce     = blockAccess.GetLiquidBlock(posX, (int)(pos.Y), posZ);
            Block middleWOIBlock = blockAccess.GetLiquidBlock(posX, (int)(pos.Y + entity.SwimmingOffsetY), posZ);

            entity.OnGround     = (entity.CollidedVertically && falling && !controls.IsClimbing) || controls.IsStepping;
            entity.FeetInLiquid = false;
            if (waterOrIce.IsLiquid())
            {
                Block aboveblock = blockAccess.GetLiquidBlock(posX, (int)(pos.Y + 1), posZ);
                entity.FeetInLiquid = ((waterOrIce.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y);
            }
            entity.InLava   = block.LiquidCode == "lava";
            entity.Swimming = middleWOIBlock.IsLiquid();

            if (!onGroundBefore && entity.OnGround)
            {
                entity.OnFallToGround(prevYMotion);
            }

            if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming))
            {
                entity.OnCollideWithLiquid();
            }

            if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming))
            {
                entity.OnExitedLiquid();
            }

            if (!falling || entity.OnGround || controls.IsClimbing)
            {
                entity.PositionBeforeFalling.Set(outposition);
            }

            profiler.Mark("apply-collisionandflags");

            Cuboidd testedEntityBox = collisionTester.entityBox;

            int xMax = (int)testedEntityBox.X2;
            int yMax = (int)testedEntityBox.Y2;
            int zMax = (int)testedEntityBox.Z2;
            int zMin = (int)testedEntityBox.Z1;

            for (int y = (int)testedEntityBox.Y1; y <= yMax; y++)
            {
                for (int x = (int)testedEntityBox.X1; x <= xMax; x++)
                {
                    for (int z = zMin; z <= zMax; z++)
                    {
                        collisionTester.tmpPos.Set(x, y, z);
                        collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1);

                        if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox))
                        {
                            // Saves us a few cpu cycles
                            if (x == (int)pos.X && z == (int)pos.Z && y == (int)pos.Y)
                            {
                                block.OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                                continue;
                            }

                            blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                        }
                    }
                }
            }
            profiler.Mark("trigger-insideblock");
        }