Beispiel #1
0
        static int FindYAbove(Level lvl, ushort x, ushort y, ushort z)
        {
            for (; y <= lvl.Height; y++)
            {
                BlockID above = lvl.GetBlock(x, (ushort)(y + 1), z);
                if (above == Block.Invalid)
                {
                    continue;
                }
                if (!CollideType.IsSolid(lvl.CollideType(above)))
                {
                    continue;
                }

                int             posY = (y + 1) * 32 - 6;
                BlockDefinition def  = lvl.GetBlockDef(above);
                if (def != null)
                {
                    posY += def.MinZ * 2;
                }

                return(posY);
            }
            return(-1);
        }
Beispiel #2
0
        static bool SolidAt(Level lvl, ushort x, int y, ushort z)
        {
            if (y >= lvl.Height)
            {
                return(false);
            }
            BlockID block = lvl.GetBlock(x, (ushort)y, z);

            return(CollideType.IsSolid(lvl.CollideType(block)));
        }
Beispiel #3
0
        public static int FindIntersectingSolids(AABB bb, Level lvl, ref AABB[] aabbs)
        {
            Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
            int     volume = (max.X - min.X + 1) * (max.Y - min.Y + 1) * (max.Z - min.Z + 1);

            if (volume > aabbs.Length)
            {
                aabbs = new AABB[volume];
            }
            int count = 0;

            for (int y = min.Y; y <= max.Y; y++)
            {
                for (int z = min.Z; z <= max.Z; z++)
                {
                    for (int x = min.X; x <= max.X; x++)
                    {
                        BlockID block   = lvl.GetBlock((ushort)x, (ushort)y, (ushort)z);
                        AABB    blockBB = lvl.blockAABBs[block];

                        blockBB.Min.X += x * 32; blockBB.Min.Y += y * 32; blockBB.Min.Z += z * 32;
                        blockBB.Max.X += x * 32; blockBB.Max.Y += y * 32; blockBB.Max.Z += z * 32;
                        if (!AABB.Intersects(ref bb, ref blockBB))
                        {
                            continue;
                        }

                        BlockDefinition def   = lvl.GetBlockDef(block);
                        bool            solid = false;

                        if (def != null)
                        {
                            solid = CollideType.IsSolid(def.CollideType);
                        }
                        else
                        {
                            solid = block == Block.Invalid || !Block.Walkthrough(Block.Convert(block));
                        }
                        if (!solid)
                        {
                            continue;
                        }

                        aabbs[count] = blockBB;
                        count++;
                    }
                }
            }
            return(count);
        }
Beispiel #4
0
        internal static void Fall(Player p, AABB bb, bool movingDown)
        {
            // Client position is slightly more precise than server's
            // If don't adjust, it's possible for player to land on edge of a block and not die
            // Only do when not moving down, so hitting a pillar while falling doesn't trigger
            if (!movingDown)
            {
                bb.Min.X -= 1; bb.Max.X += 1;
                bb.Min.Z -= 1; bb.Max.Z += 1;
            }

            bb.Min.Y -= 2; // test block below player feet
            Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
            bool    allGas = true;

            for (int z = min.Z; z <= max.Z; z++)
            {
                for (int x = min.X; x <= max.X; x++)
                {
                    BlockID block   = GetSurvivalBlock(p, x, min.Y, z);
                    byte    collide = p.level.CollideType(block);
                    allGas = allGas && collide == CollideType.WalkThrough;
                    if (!CollideType.IsSolid(collide))
                    {
                        continue;
                    }

                    int fallHeight = p.startFallY - bb.Min.Y;
                    if (fallHeight > p.level.Config.FallHeight * 32)
                    {
                        p.HandleDeath(Block.Air, null, false, true);
                    }

                    p.startFallY = -1;
                    return;
                }
            }

            if (!allGas)
            {
                return;
            }
            if (bb.Min.Y > p.lastFallY)
            {
                p.startFallY = -1;                         // flying up resets fall height
            }
            p.startFallY = Math.Max(bb.Min.Y, p.startFallY);
        }
Beispiel #5
0
        /// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary>
        /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks>
        /// <returns> Return code from DoBlockchange </returns>
        public ChangeResult ChangeBlock(ushort x, ushort y, ushort z, BlockID block)
        {
            BlockID      old    = level.GetBlock(x, y, z);
            ChangeResult result = level.DoBlockchange(this, x, y, z, block);

            if (result == ChangeResult.Unchanged)
            {
                return(result);
            }
            if (result == ChangeResult.Modified)
            {
                level.BroadcastChange(x, y, z, block);
            }

            ushort flags = BlockDBFlags.ManualPlace;

            if (painting && CollideType.IsSolid(level.CollideType(old)))
            {
                flags = BlockDBFlags.Painted;
            }

            level.BlockDB.Cache.Add(this, x, y, z, flags, old, block);
            y--; // check for growth at block below

            bool grow = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5);

            if (!grow || level.CanAffect(this, x, y, z) != null)
            {
                return(result);
            }
            BlockID below = level.GetBlock(x, y, z);

            BlockID grass = level.Props[below].GrassBlock;

            if (grass != Block.Invalid && block == Block.Air)
            {
                level.Blockchange(this, x, y, z, grass);
            }

            BlockID dirt = level.Props[below].DirtBlock;

            if (dirt != Block.Invalid && !level.LightPasses(block))
            {
                level.Blockchange(this, x, y, z, dirt);
            }
            return(result);
        }
Beispiel #6
0
        /// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary>
        /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks>
        /// <returns> Return code from DoBlockchange </returns>
        public int ChangeBlock(ushort x, ushort y, ushort z, BlockID block)
        {
            BlockID old  = level.GetBlock(x, y, z);
            int     type = level.DoBlockchange(this, x, y, z, block);

            if (type == 0)
            {
                return(type);                                               // no change performed
            }
            if (type == 2)
            {
                Player.GlobalBlockchange(level, x, y, z, block);            // different visually
            }
            ushort flags = BlockDBFlags.ManualPlace;

            if (painting && CollideType.IsSolid(level.CollideType(old)))
            {
                flags = BlockDBFlags.Painted;
            }

            level.BlockDB.Cache.Add(this, x, y, z, flags, old, block);
            y--; // check for growth at block below

            bool grow = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5);

            if (!grow || level.CanAffect(this, x, y, z) != null)
            {
                return(type);
            }
            BlockID below = level.GetBlock(x, y, z);

            BlockID grass = level.Props[below].GrassBlock;

            if (grass != Block.Invalid && block == Block.Air)
            {
                level.Blockchange(this, x, y, z, grass);
            }

            BlockID dirt = level.Props[below].DirtBlock;

            if (dirt != Block.Invalid && !level.LightPasses(block))
            {
                level.Blockchange(this, x, y, z, dirt);
            }
            return(type);
        }
Beispiel #7
0
        static int FindYAbove(Level lvl, ushort x, ushort y, ushort z)
        {
            bool foundAnySolid = false;
            for (ushort yCheck = y; yCheck < lvl.Height; yCheck++) {
                BlockID block = lvl.GetBlock(x, yCheck, z);
                if (block != Block.Invalid &&
                    CollideType.IsSolid(lvl.CollideType(block))) { foundAnySolid = true; continue; }

                BlockID above = lvl.GetBlock(x, (ushort)(yCheck + 1), z);
                if (above != Block.Invalid &&
                    CollideType.IsSolid(lvl.CollideType(above))) { foundAnySolid = true; continue; }

                BlockID below = lvl.GetBlock(x, (ushort)(yCheck - 1), z);
                if (below != Block.Invalid &&
                    CollideType.IsSolid(lvl.CollideType(below)) && yCheck > y) return yCheck;
            }
            return foundAnySolid ? lvl.Height : -1;
        }
Beispiel #8
0
        /// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary>
        /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks>
        /// <returns> Return code from DoBlockchange </returns>
        public int ChangeBlock(ushort x, ushort y, ushort z, ExtBlock block)
        {
            ExtBlock old  = level.GetBlock(x, y, z);
            int      type = level.DoBlockchange(this, x, y, z, block);

            if (type == 0)
            {
                return(type);                                               // no change performed
            }
            if (type == 2)
            {
                Player.GlobalBlockchange(level, x, y, z, block);            // different visually
            }
            ushort flags = BlockDBFlags.ManualPlace;

            if (painting && CollideType.IsSolid(level.CollideType(old)))
            {
                flags = BlockDBFlags.Painted;
            }
            level.BlockDB.Cache.Add(this, x, y, z, flags, old, block);

            bool autoGrass = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5);

            if (!autoGrass)
            {
                return(type);
            }
            ExtBlock below = level.GetBlock(x, (ushort)(y - 1), z);

            ushort grassIdx = level.Props[below.Index].GrassIndex;

            if (grassIdx != Block.Invalid && block.BlockID == Block.Air)
            {
                level.Blockchange(this, x, (ushort)(y - 1), z, ExtBlock.FromIndex(grassIdx));
            }

            ushort dirtIdx = level.Props[below.Index].DirtIndex;

            if (dirtIdx != Block.Invalid && !level.LightPasses(block))
            {
                level.Blockchange(this, x, (ushort)(y - 1), z, ExtBlock.FromIndex(dirtIdx));
            }
            return(type);
        }
Beispiel #9
0
        public static bool IntersectsSolidBlocks(AABB bb, Level lvl)
        {
            Vec3S32 min = bb.BlockMin, max = bb.BlockMax;

            for (int y = min.Y; y <= max.Y; y++)
            {
                for (int z = min.Z; z <= max.Z; z++)
                {
                    for (int x = min.X; x <= max.X; x++)
                    {
                        ushort   xP = (ushort)x, yP = (ushort)y, zP = (ushort)z;
                        ExtBlock block = lvl.GetBlock(xP, yP, zP);

                        AABB blockBB = lvl.blockAABBs[block.Index].Offset(x * 32, y * 32, z * 32);
                        if (!AABB.Intersects(ref bb, ref blockBB))
                        {
                            continue;
                        }

                        BlockDefinition def = lvl.GetBlockDef(block);
                        if (def != null)
                        {
                            if (CollideType.IsSolid(def.CollideType))
                            {
                                return(true);
                            }
                        }
                        else if (block.BlockID == Block.Invalid)
                        {
                            if (y < lvl.Height)
                            {
                                return(true);
                            }
                        }
                        else if (!Block.Walkthrough(Block.Convert(block.BlockID)))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Beispiel #10
0
        internal static void Fall(Player p, AABB bb)
        {
            bb.Min.Y -= 2; // test block below player feet
            Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
            bool    allGas = true;

            for (int z = min.Z; z <= max.Z; z++)
            {
                for (int x = min.X; x <= max.X; x++)
                {
                    ExtBlock block   = GetSurvivalBlock(p, x, min.Y, z);
                    byte     collide = p.level.CollideType(block);
                    allGas = allGas && collide == CollideType.WalkThrough;
                    if (!CollideType.IsSolid(collide))
                    {
                        continue;
                    }

                    int fallHeight = p.startFallY - bb.Min.Y;
                    if (fallHeight > p.level.Config.FallHeight * 32)
                    {
                        p.HandleDeath(ExtBlock.Air, null, false, true);
                    }

                    p.startFallY = -1;
                    return;
                }
            }

            if (!allGas)
            {
                return;
            }
            if (bb.Min.Y > p.lastFallY)
            {
                p.startFallY = -1;                         // flying up resets fall height
            }
            p.startFallY = Math.Max(bb.Min.Y, p.startFallY);
        }
Beispiel #11
0
        static int FindYAbove(Level lvl, ushort x, ushort y, ushort z)
        {
            for (; y < lvl.Height; y++)
            {
                BlockID block = lvl.GetBlock(x, y, z);
                if (block != Block.Invalid && CollideType.IsSolid(lvl.CollideType(block)))
                {
                    continue;
                }

                BlockID above = lvl.GetBlock(x, (ushort)(y + 1), z);
                if (above != Block.Invalid && CollideType.IsSolid(lvl.CollideType(above)))
                {
                    continue;
                }

                BlockID below = lvl.GetBlock(x, (ushort)(y - 1), z);
                if (below != Block.Invalid && CollideType.IsSolid(lvl.CollideType(below)))
                {
                    return(y);
                }
            }
            return(-1);
        }
Beispiel #12
0
        static int FindYBelow(Level lvl, ushort x, ushort y, ushort z)
        {
            for (; y > 0; y--)
            {
                ExtBlock block = lvl.GetBlock(x, y, z);
                if (!block.IsInvalid && CollideType.IsSolid(lvl.CollideType(block)))
                {
                    continue;
                }

                ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z);
                if (!above.IsInvalid && CollideType.IsSolid(lvl.CollideType(above)))
                {
                    continue;
                }

                ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z);
                if (!below.IsInvalid && CollideType.IsSolid(lvl.CollideType(below)))
                {
                    return(y);
                }
            }
            return(-1);
        }
Beispiel #13
0
        public bool HitTestMap()
        {
            Level map = LevelInfo.FindExact(_curMap);

            int minX = _pos.X / 32 - 2;
            int maxX = _pos.X / 32 + 2;

            int minY = _pos.Y / 32 - 2;
            int maxY = _pos.Y / 32 + 2;

            int minZ = _pos.Z / 32 - 2;
            int maxZ = _pos.Z / 32 + 2;

            for (int i = minY; i <= maxY; i++)
            {
                for (int j = minX; j <= maxX; j++)
                {
                    for (int k = minZ; k <= maxZ; k++)
                    {
                        if (!CollideType.IsSolid(map.CollideType((map.GetBlock((ushort)(j), (ushort)(i), (ushort)(k))))))
                        {
                            continue;
                        }
                        bool touchX = _pos.X + _width > (j * 32) && _pos.X < ((j + 1) * 32);
                        bool touchY = (_pos.Y - 32) + _height > (i * 32) && (_pos.Y - 32) < ((i + 1) * 32);
                        bool touchZ = _pos.Z + _width > (k * 32) && _pos.Z < ((k + 1) * 32);
                        if (touchX && touchY && touchZ)
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }