Ejemplo n.º 1
0
        private bool TryPlace(Block block, int dx, int dy, int dz)
        {
            IBlockAccessor blockAccess = entity.World.BlockAccessor;
            BlockPos       pos         = entity.ServerPos.XYZ.AsBlockPos.Add(dx, dy, dz);

            if (blockAccess.GetLiquidBlock(pos).IsLiquid())
            {
                return(false);
            }
            if (!blockAccess.GetBlock(pos).IsReplacableBy(block))
            {
                return(false);
            }

            pos.Y--;
            if (blockAccess.GetSolidBlock(pos.X, pos.Y, pos.Z).CanAttachBlockAt(blockAccess, block, pos, BlockFacing.UP))
            {
                pos.Y++;
                blockAccess.SetBlock(block.BlockId, pos);

                // Instantly despawn the block again if it expired already
                BlockEntityTransient betran = blockAccess.GetBlockEntity(pos) as BlockEntityTransient;
                betran?.SetPlaceTime(entity.World.Calendar.TotalHours);

                if (betran?.IsDueTransition() == true)
                {
                    blockAccess.SetBlock(0, pos);
                }

                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
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");
        }