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);
                }
            }
        }
        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.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);
                }
            }
        }