示例#1
0
        static bool PickBlock(Game game, PickedPos pos)
        {
            if (!game.CanPick(t.Block))
            {
                return(false);
            }

            // This cell falls on the path of the ray. Now perform an additional bounding box test,
            // since some blocks do not occupy a whole cell.
            float t0, t1;

            if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1))
            {
                return(false);
            }
            Vector3 I = t.Origin + t.Dir * t0;

            // Only pick the block if the block is precisely within reach distance.
            float lenSq = (I - t.Origin).LengthSquared;
            float reach = game.LocalPlayer.ReachDistance;

            if (lenSq <= reach * reach)
            {
                pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I);
            }
            else
            {
                pos.SetAsInvalid();
            }
            return(true);
        }
示例#2
0
        // http://www.xnawiki.com/index.php/Voxel_traversal
        // https://web.archive.org/web/20120113051728/http://www.xnawiki.com/index.php?title=Voxel_traversal
        /// <summary> Determines the picked block based on the given origin and direction vector.<br/>
        /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
        /// or not being able to find a suitable candiate within the given reach distance. </summary>
        public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            // Implementation based on: "A Fast Voxel Traversal Algorithm for Ray Tracing"
            // John Amanatides, Andrew Woo
            // http://www.cse.yorku.ca/~amana/research/grid.pdf
            // http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf

            // The cell in which the ray starts.
            Vector3I start = Vector3I.Floor(origin);               // Rounds the position's X, Y and Z down to the nearest integer values.
            int      x = start.X, y = start.Y, z = start.Z;
            Vector3I step, cellBoundary;
            Vector3  tMax, tDelta;

            CalcVectors(origin, dir, out step, out cellBoundary, out tMax, out tDelta);

            Map       map          = game.Map;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;

            // For each step, determine which distance to the next voxel boundary is lowest (i.e.
            // which voxel boundary is nearest) and walk that way.
            while (iterations < 10000)
            {
                byte    block = GetBlock(map, x, y, z, origin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid();
                    return;
                }

                if (game.CanPick(block))
                {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);
                        return;
                    }
                }
                Step(ref tMax, ref tDelta, ref step, ref x, ref y, ref z);
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
        /// <summary> Determines the picked block based on the given origin and direction vector.<br/>
        /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
        /// or not being able to find a suitable candiate within the given reach distance. </summary>
        public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            tracer.SetRayData(origin, dir);
            World     map          = game.World;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;
            Vector3I  pOrigin      = Vector3I.Floor(origin);

            while (iterations < 10000)
            {
                int     x = tracer.X, y = tracer.Y, z = tracer.Z;
                byte    block = GetBlock(map, x, y, z, pOrigin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];
                if (info.IsLiquid[block])
                {
                    min.Y -= 1.5f / 16; max.Y -= 1.5f / 16;
                }

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid(); return;
                }

                if (game.CanPick(block))
                {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);
                        return;
                    }
                }
                tracer.Step();
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
        static bool PickBlock(Game game, PickedPos pos)
        {
            if (!game.CanPick(t.Block))
            {
                return(false);
            }

            // This cell falls on the path of the ray. Now perform an additional bounding box test,
            // since some blocks do not occupy a whole cell.
            float t0, t1;

            if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1))
            {
                return(false);
            }
            Vector3 I = t.Origin + t.Dir * t0;

            pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I);
            return(true);
        }
示例#5
0
        /// <summary> Determines the picked block based on the given origin and direction vector.<br/>
        /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
        /// or not being able to find a suitable candiate within the given reach distance. </summary>
        public static void CalculatePickedBlock( Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos )
        {
            tracer.SetRayData( origin, dir );
            World map = game.World;
            BlockInfo info = game.BlockInfo;
            float reachSquared = reach * reach;
            int iterations = 0;
            Vector3I pOrigin = Vector3I.Floor( origin );

            while( iterations < 10000 ) {
                int x = tracer.X, y = tracer.Y, z = tracer.Z;
                byte block = GetBlock( map, x, y, z, pOrigin );
                Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
                Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];

                float dx = Math.Min( Math.Abs( origin.X - min.X ), Math.Abs( origin.X - max.X ) );
                float dy = Math.Min( Math.Abs( origin.Y - min.Y ), Math.Abs( origin.Y - max.Y ) );
                float dz = Math.Min( Math.Abs( origin.Z - min.Z ), Math.Abs( origin.Z - max.Z ) );

                if( dx * dx + dy * dy + dz * dz > reachSquared ) {
                    pickedPos.SetAsInvalid(); return;
                }

                if( game.CanPick( block ) ) {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if( Intersection.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid( x, y, z, min, max, block, intersect );
                        return;
                    }
                }
                tracer.Step();
                iterations++;
            }
            throw new InvalidOperationException( "did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")" );
        }
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                      // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                input.pickingId = -1;
                input.ButtonStateChanged(MouseButton.Left, left);
                input.ButtonStateChanged(MouseButton.Right, right);
                input.ButtonStateChanged(MouseButton.Middle, middle);
            }

            if (game.Gui.ActiveScreen.HandlesAllInput || !inv.CanPick)
            {
                return;
            }

            if (left)
            {
                // always play delete animations, even if we aren't picking a block.
                game.HeldBlockRenderer.ClickAnim(true);

                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                if (BlockInfo.Draw[old] == DrawType.Gas || !BlockInfo.CanDelete[old])
                {
                    return;
                }

                game.UpdateBlock(pos.X, pos.Y, pos.Z, Block.Air);
                game.UserEvents.RaiseBlockChanged(pos, old, Block.Air);
            }
            else if (right)
            {
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old   = game.World.GetBlock(pos);
                BlockID block = inv.Selected;
                if (game.AutoRotate)
                {
                    block = AutoRotate.RotateBlock(game, block);
                }

                if (game.CanPick(old) || !BlockInfo.CanPlace[block])
                {
                    return;
                }
                // air-ish blocks can only replace over other air-ish blocks
                if (BlockInfo.Draw[block] == DrawType.Gas && BlockInfo.Draw[old] != DrawType.Gas)
                {
                    return;
                }

                if (!PickingHandler.CheckIsFree(game, block))
                {
                    return;
                }
                game.UpdateBlock(pos.X, pos.Y, pos.Z, block);
                game.UserEvents.RaiseBlockChanged(pos, old, block);
            }
            else if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }
                BlockID cur = game.World.GetBlock(pos);

                if (BlockInfo.Draw[cur] == DrawType.Gas)
                {
                    return;
                }
                if (!(BlockInfo.CanPlace[cur] || BlockInfo.CanDelete[cur]))
                {
                    return;
                }
                if (!inv.CanChangeSelected() || inv.Selected == cur)
                {
                    return;
                }

                // Is the currently selected block an empty slot
                if (inv[inv.SelectedIndex] == Block.Air)
                {
                    inv.Selected = cur; return;
                }
                // Try to replace same block
                for (int i = 0; i < Inventory.BlocksPerRow; i++)
                {
                    if (inv[i] != cur)
                    {
                        continue;
                    }
                    inv.SelectedIndex = i; return;
                }
                // Try to replace empty slots
                for (int i = 0; i < Inventory.BlocksPerRow; i++)
                {
                    if (inv[i] != Block.Air)
                    {
                        continue;
                    }
                    inv[i]            = cur;
                    inv.SelectedIndex = i; return;
                }
                // Finally, replace the currently selected block.
                inv.Selected = cur;
            }
        }
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                       // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Network.UsingPlayerClick && !game.ScreenLockedInput)
            {
                byte targetId = game.Players.GetClosetPlayer(game.LocalPlayer);
                ButtonStateChanged(MouseButton.Left, left, targetId);
                ButtonStateChanged(MouseButton.Right, right, targetId);
                ButtonStateChanged(MouseButton.Middle, middle, targetId);
            }

            int buttonsDown = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0);

            if (buttonsDown > 1 || game.ScreenLockedInput || inv.HeldBlock == Block.Air)
            {
                return;
            }

            // always play delete animations, even if we aren't picking a block.
            if (left)
            {
                game.BlockHandRenderer.SetAnimationClick(true);
            }
            if (!game.SelectedPos.Valid)
            {
                return;
            }

            if (middle)
            {
                Vector3I pos   = game.SelectedPos.BlockPos;
                byte     block = 0;
                if (game.Map.IsValidPos(pos) && (block = game.Map.GetBlock(pos)) != 0 &&
                    (inv.CanPlace[block] || inv.CanDelete[block]))
                {
                    for (int i = 0; i < inv.Hotbar.Length; i++)
                    {
                        if (inv.Hotbar[i] == (Block)block)
                        {
                            inv.HeldBlockIndex = i; return;
                        }
                    }
                    inv.HeldBlock = (Block)block;
                }
            }
            else if (left)
            {
                Vector3I pos   = game.SelectedPos.BlockPos;
                byte     block = 0;
                if (game.Map.IsValidPos(pos) && (block = game.Map.GetBlock(pos)) != 0 &&
                    inv.CanDelete[block])
                {
                    game.ParticleManager.BreakBlockEffect(pos, block);
                    game.AudioPlayer.PlayDigSound(game.BlockInfo.DigSounds[block]);
                    game.UpdateBlock(pos.X, pos.Y, pos.Z, 0);
                    game.Network.SendSetBlock(pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock);
                }
            }
            else if (right)
            {
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.Map.IsValidPos(pos))
                {
                    return;
                }

                byte block = (byte)inv.HeldBlock;
                if (!game.CanPick(game.Map.GetBlock(pos)) && inv.CanPlace[block] &&
                    CheckIsFree(game.SelectedPos, block))
                {
                    game.UpdateBlock(pos.X, pos.Y, pos.Z, block);
                    game.Network.SendSetBlock(pos.X, pos.Y, pos.Z, true, block);
                    game.BlockHandRenderer.SetAnimationClick(false);
                }
            }
        }
示例#8
0
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                      // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                input.pickingId = -1;
                input.ButtonStateChanged(MouseButton.Left, left);
                input.ButtonStateChanged(MouseButton.Right, right);
                input.ButtonStateChanged(MouseButton.Middle, middle);
            }

            if (game.Gui.ActiveScreen.HandlesAllInput || !inv.CanPick)
            {
                return;
            }

            if (left)
            {
                if (game.Mode.PickingLeft())
                {
                    return;
                }
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                if (BlockInfo.Draw[old] == DrawType.Gas || !BlockInfo.CanDelete[old])
                {
                    return;
                }
                game.Mode.PickLeft(old);
            }
            else if (right)
            {
                if (game.Mode.PickingRight())
                {
                    return;
                }
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old   = game.World.GetBlock(pos);
                BlockID block = inv.Selected;
                if (game.AutoRotate)
                {
                    block = AutoRotate.RotateBlock(game, block);
                }

                if (game.CanPick(old) || !BlockInfo.CanPlace[block])
                {
                    return;
                }
                // air-ish blocks can only replace over other air-ish blocks
                if (BlockInfo.Draw[block] == DrawType.Gas && BlockInfo.Draw[old] != DrawType.Gas)
                {
                    return;
                }

                if (!PickingHandler.CheckIsFree(game, block))
                {
                    return;
                }
                game.Mode.PickRight(old, block);
            }
            else if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                game.Mode.PickMiddle(old);
            }
        }
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                       // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                byte targetId = game.Entities.GetClosetPlayer(game.LocalPlayer);
                input.ButtonStateChanged(MouseButton.Left, left, targetId);
                input.ButtonStateChanged(MouseButton.Right, right, targetId);
                input.ButtonStateChanged(MouseButton.Middle, middle, targetId);
            }

            int buttonsDown = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0);

            if (buttonsDown > 1 || game.Gui.ActiveScreen.HandlesAllInput ||
                inv.HeldBlock == Block.Air)
            {
                return;
            }

            // always play delete animations, even if we aren't picking a block.
            if (left)
            {
                game.HeldBlockRenderer.anim.SetClickAnim(true);
            }
            if (!game.SelectedPos.Valid)
            {
                return;
            }
            BlockInfo info = game.BlockInfo;

            if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }
                byte old = game.World.GetBlock(pos);

                if (!info.IsAir[old] && (inv.CanPlace[old] || inv.CanDelete[old]))
                {
                    for (int i = 0; i < inv.Hotbar.Length; i++)
                    {
                        if (inv.Hotbar[i] == old)
                        {
                            inv.HeldBlockIndex = i; return;
                        }
                    }
                    inv.HeldBlock = old;
                }
            }
            else if (left)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }
                byte old = game.World.GetBlock(pos);

                if (!info.IsAir[old] && inv.CanDelete[old])
                {
                    game.UpdateBlock(pos.X, pos.Y, pos.Z, 0);
                    game.UserEvents.RaiseBlockChanged(pos, old, 0);
                }
            }
            else if (right)
            {
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }
                byte old   = game.World.GetBlock(pos);
                byte block = (byte)inv.HeldBlock;

                if (!game.CanPick(old) && inv.CanPlace[block] && CheckIsFree(game.SelectedPos, block))
                {
                    game.UpdateBlock(pos.X, pos.Y, pos.Z, block);
                    game.UserEvents.RaiseBlockChanged(pos, old, block);
                }
            }
        }
示例#10
0
        // http://www.xnawiki.com/index.php/Voxel_traversal
        public static void GetPickedBlockPos( Game window, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos )
        {
            // Implementation is based on:
            // "A Fast Voxel Traversal Algorithm for Ray Tracing"
            // John Amanatides, Andrew Woo
            // http://www.cse.yorku.ca/~amana/research/grid.pdf
            // http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf

            // NOTES:
            // * This code assumes that the ray's position and direction are in 'cell coordinates', which means
            //   that one unit equals one cell in all directions.
            // * When the ray doesn't start within the voxel grid, calculate the first position at which the
            //   ray could enter the grid. If it never enters the grid, there is nothing more to do here.
            // * Also, it is important to test when the ray exits the voxel grid when the grid isn't infinite.
            // * The Point3D structure is a simple structure having three integer fields (X, Y and Z).

            // The cell in which the ray starts.
            Vector3I start = Vector3I.Floor( origin ); // Rounds the position's X, Y and Z down to the nearest integer values.
            int x = start.X;
            int y = start.Y;
            int z = start.Z;

            // Determine which way we go.
            int stepX = Math.Sign( dir.X );
            int stepY = Math.Sign( dir.Y );
            int stepZ = Math.Sign( dir.Z );

            // Calculate cell boundaries. When the step (i.e. direction sign) is positive,
            // the next boundary is AFTER our current position, meaning that we have to add 1.
            // Otherwise, it is BEFORE our current position, in which case we add nothing.
            Vector3I cellBoundary = new Vector3I(
                x + ( stepX > 0 ? 1 : 0 ),
                y + ( stepY > 0 ? 1 : 0 ),
                z + ( stepZ > 0 ? 1 : 0 ) );

            // NOTE: For the following calculations, the result will be Single.PositiveInfinity
            // when ray.Direction.X, Y or Z equals zero, which is OK. However, when the left-hand
            // value of the division also equals zero, the result is Single.NaN, which is not OK.

            // Determine how far we can travel along the ray before we hit a voxel boundary.
            Vector3 tMax = new Vector3(
                ( cellBoundary.X - origin.X ) / dir.X,    // Boundary is a plane on the YZ axis.
                ( cellBoundary.Y - origin.Y ) / dir.Y,    // Boundary is a plane on the XZ axis.
                ( cellBoundary.Z - origin.Z ) / dir.Z );  // Boundary is a plane on the XY axis.
            if( Single.IsNaN( tMax.X ) || Single.IsInfinity( tMax.X ) ) tMax.X = Single.PositiveInfinity;
            if( Single.IsNaN( tMax.Y ) || Single.IsInfinity( tMax.Y ) ) tMax.Y = Single.PositiveInfinity;
            if( Single.IsNaN( tMax.Z ) || Single.IsInfinity( tMax.Z ) ) tMax.Z = Single.PositiveInfinity;

            // Determine how far we must travel along the ray before we have crossed a gridcell.
            Vector3 tDelta = new Vector3(
                stepX / dir.X,     // Crossing the width of a cell.
                stepY / dir.Y,     // Crossing the height of a cell.
                stepZ / dir.Z );   // Crossing the depth of a cell.
            if( Single.IsNaN( tDelta.X ) ) tDelta.X = Single.PositiveInfinity;
            if( Single.IsNaN( tDelta.Y ) ) tDelta.Y = Single.PositiveInfinity;
            if( Single.IsNaN( tDelta.Z ) ) tDelta.Z = Single.PositiveInfinity;

            Map map = window.Map;
            BlockInfo info = window.BlockInfo;
            float reachSquared = reach * reach;
            int iterations = 0;

            // For each step, determine which distance to the next voxel boundary is lowest (i.e.
            // which voxel boundary is nearest) and walk that way.
            while( iterations < 10000 ) {
                byte block = GetBlock( map, x, y, z, origin );
                Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
                Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];

                float dx = Math.Min( Math.Abs( origin.X - min.X ), Math.Abs( origin.X - max.X ) );
                float dy = Math.Min( Math.Abs( origin.Y - min.Y ), Math.Abs( origin.Y - max.Y ) );
                float dz = Math.Min( Math.Abs( origin.Z - min.Z ), Math.Abs( origin.Z - max.Z ) );

                if( dx * dx + dy * dy + dz * dz > reachSquared ) {
                    pickedPos.SetAsInvalid();
                    return;
                }

                if( window.CanPick( block ) ) {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if( Intersection.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid( min, max, block, intersect );
                        return;
                    }
                }

                if( tMax.X < tMax.Y && tMax.X < tMax.Z ) {
                    // tMax.X is the lowest, an YZ cell boundary plane is nearest.
                    x += stepX;
                    tMax.X += tDelta.X;
                } else if( tMax.Y < tMax.Z ) {
                    // tMax.Y is the lowest, an XZ cell boundary plane is nearest.
                    y += stepY;
                    tMax.Y += tDelta.Y;
                } else {
                    // tMax.Z is the lowest, an XY cell boundary plane is nearest.
                    z += stepZ;
                    tMax.Z += tDelta.Z;
                }
                iterations++;
            }
            throw new InvalidOperationException( "did over 10000 iterations in GetPickedBlockPos(). " +
                                                "Something has gone wrong. (dir: " + dir + ")" );
        }
示例#11
0
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                      // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                input.pickingId = -1;
                input.ButtonStateChanged(MouseButton.Left, left);
                input.ButtonStateChanged(MouseButton.Right, right);
                input.ButtonStateChanged(MouseButton.Middle, middle);
            }

            int btns = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0);

            if (btns > 1 || game.Gui.ActiveScreen.HandlesAllInput || inv.Selected == Block.Invalid)
            {
                return;
            }

            // always play delete animations, even if we aren't picking a block.
            if (left)
            {
                game.HeldBlockRenderer.anim.SetClickAnim(true);
                byte id = game.Entities.GetClosetPlayer(game.LocalPlayer);
                if (id != EntityList.SelfID && game.Mode.PickEntity(id))
                {
                    return;
                }
            }
            if (!game.SelectedPos.Valid)
            {
                return;
            }

            if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                game.Mode.PickMiddle(old);
            }
            else if (left)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                if (game.BlockInfo.Draw[old] == DrawType.Gas || !inv.CanDelete[old])
                {
                    return;
                }
                game.Mode.PickLeft(old);
            }
            else if (right)
            {
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old   = game.World.GetBlock(pos);
                BlockID block = inv.Selected;
                block = AutoRotate.RotateBlock(game, block);

                if (game.CanPick(old))
                {
                    return;
                }
                if (!inv.CanPlace[block] && game.SelectedPos.Block != Block.Chest1 && game.SelectedPos.Block != Block.Chest2 && game.SelectedPos.Block != Block.Chest3 && game.SelectedPos.Block != Block.Chest4)
                {
                    return;
                }
                if (!PickingHandler.CheckIsFree(game, block))
                {
                    return;
                }
                game.Mode.PickRight(old, block);
            }
        }