How do I force a player to mine a block?

Discussion in 'Plugin Development' started by BaddCamden, Feb 28, 2021.

  1. Offline

    BaddCamden

    I have made a plugin that allows me to configure the mining speed of blocks by simulating the block breaking animation whilst preventing the player from mining the block, however I need a way to make the player mine the block after the block breaking animation has finished. I don't mean to break the block naturally or call the event after the block is broken, I mean to make EVERYTHING be as if the player has broken the block. Particles, events, packets, everything. Any help?

    (I need everything for additional plugins I am creating in the future which require that compatibility)


    Also any additional suggestions to my code would be greatly appreciated!

    Code:
    Code:
    package me.BaddCamden.MainSkyblock;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.logging.Logger;
    import org.bukkit.Bukkit;
    import org.bukkit.Material;
    import org.bukkit.block.Block;
    import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.BlockBreakEvent;
    import org.bukkit.event.block.BlockDamageEvent;
    import org.bukkit.potion.PotionEffect;
    import org.bukkit.potion.PotionEffectType;
    import org.bukkit.scheduler.BukkitScheduler;
    import com.comphenix.protocol.PacketType;
    import com.comphenix.protocol.ProtocolLibrary;
    import com.comphenix.protocol.ProtocolManager;
    import com.comphenix.protocol.events.ListenerPriority;
    import com.comphenix.protocol.events.PacketAdapter;
    import com.comphenix.protocol.events.PacketContainer;
    import com.comphenix.protocol.events.PacketEvent;
    import com.comphenix.protocol.wrappers.EnumWrappers;
    import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
    import net.minecraft.server.v1_16_R3.PacketPlayInBlockDig;
    import net.minecraft.server.v1_16_R3.BlockPosition;
    import net.minecraft.server.v1_16_R3.Packet;
    import net.minecraft.server.v1_16_R3.PacketPlayOutBlockBreakAnimation;
    public class MiningSpeed implements Listener{
       
        //Configure this code to change speeds which blocks are mined! I will later add this to the config...
        ArrayList<Material> configurableBlocks = new ArrayList<Material>(Arrays.asList(Material.DIRT,Material.GRASS_BLOCK,Material.OAK_LOG,Material.STONE,Material.BIRCH_LOG,Material.SPRUCE_LOG,Material.ACACIA_LOG,Material.JUNGLE_LOG,Material.DARK_OAK_LOG));   
        ArrayList<Integer> configurableBreakTime = new ArrayList<Integer>(Arrays.asList(60,         90,                   600,              500,          60,                90,                 120,                60,                  150)); 
       
        //Arrays that tell whether a player is mining a block
        ArrayList<Player> playerMiningBlock = new ArrayList<Player>();
        ArrayList<Block> blockBeingMined = new ArrayList<Block>();
       
        Logger onLog = Bukkit.getLogger();
        private ProtocolManager protocolManager;
        Main mainPlugin;
        public MiningSpeed(Main main) {
            mainPlugin = main;
            protocolManager = ProtocolLibrary.getProtocolManager();
            interceptPackets();
        }
        private void interceptPackets(){
            onLog.info("as");
            protocolManager.addPacketListener(new PacketAdapter(mainPlugin, ListenerPriority.NORMAL, PacketType.Play.Client.BLOCK_DIG) {
                @Override
                public void onPacketReceiving(PacketEvent event){
                    PacketContainer packet = event.getPacket();
                    EnumWrappers.PlayerDigType digType = packet.getPlayerDigTypes().getValues().get(0);
                    System.out.println("DigType: "+digType.name());
                    if(digType.equals(PlayerDigType.START_DESTROY_BLOCK)) {
                        playerMiningBlock.add(event.getPlayer());
                        blockBeingMined.add(null);
                    } else {
                        for(int i = 0; i < playerMiningBlock.size(); i++) {
                            if(playerMiningBlock.get(i) == event.getPlayer()) {
                                playerMiningBlock.remove(i);
                                blockBeingMined.remove(i);
                               
                                break;
                            }
                        }
                    }
                   
                }
            });
        }
       
        @EventHandler
        public void OnBlockHit(BlockDamageEvent event) {
            for(int i = 0; i < playerMiningBlock.size(); i++) {
                if(playerMiningBlock.get(i) == event.getPlayer()) {
                    playerMiningBlock.remove(i);
                    blockBeingMined.remove(i);
                    break;
                }
            }
            if(!event.getInstaBreak()) {
                playerMiningBlock.add(event.getPlayer());
                blockBeingMined.add(event.getBlock());
                for(int i = 0; i < configurableBlocks.size(); i++) {
                    if(event.getBlock().getType().equals(configurableBlocks.get(i))) {
                        MiningBlock(event, i);
                    }
                }
            }
        }
        public void MiningBlock(BlockDamageEvent event, int i) {
            CraftPlayer p = (CraftPlayer) event.getPlayer();
            for(int a = 0; a < playerMiningBlock.size(); a++) {
                  if(playerMiningBlock.get(a) == event.getPlayer()) {
                      ((Player)p).addPotionEffect(new PotionEffect(PotionEffectType.SLOW_DIGGING, 1000, 100, true));
                      blockBreakingStages(event, p, i, 0, blockBeingMined.get(a));
                  } 
            }
           
           
        }
       
        public void SendPacket(CraftPlayer p, Packet packet) {
            try {
                Field field = packet.getClass().getDeclaredField("a");
                field.setAccessible(true);// allows us to access the field
                 
                field.setInt(packet, 123);// sets the field to an integer
                field.setAccessible(!field.isAccessible());//we want to stop accessing this now
            } catch(Exception x) {
                x.printStackTrace();
            }
            p.getHandle().playerConnection.sendPacket(packet);
        }
       
        public void blockBreakingStages(BlockDamageEvent event, CraftPlayer p, int a, int stage, Block block) {
            int temporaryBreakTime = ((Integer)configurableBreakTime.get(a) / 9);
            onLog.info(""+temporaryBreakTime);
           
            BukkitScheduler scheduler = mainPlugin.getServer().getScheduler();
              scheduler.scheduleSyncDelayedTask(mainPlugin, new Runnable() {
                  public void run() {
                      boolean foundPlayer = false;
                      for(int i = 0; i < playerMiningBlock.size(); i++) {
                          if(playerMiningBlock.get(i) == event.getPlayer() ) {
                              foundPlayer = true;
                                  if(blockBeingMined.get(i) == block) {
                                     
                                      onLog.info("It works, yes inded, please sand halp");
                                      PacketPlayOutBlockBreakAnimation packet = new PacketPlayOutBlockBreakAnimation(event.getPlayer().getEntityId(), new BlockPosition(event.getBlock().getX(), event.getBlock().getY(), event.getBlock().getZ()), stage);
                                      SendPacket(p, packet);
                                      if(stage < 9) {
                                          blockBreakingStages(event, p, a, stage + 1, block);
                                          onLog.info("WHY");
                                      } else {
                                          PacketPlayInBlockDig packetBreak = new PacketPlayInBlockDig();
                                          mainPlugin.getServer().getPluginManager().callEvent(new BlockBreakEvent((Block) event.getBlock(), event.getPlayer())); //This is where I need your help
                                          event.getBlock().breakNaturally(event.getPlayer().getItemInHand());   //This is where I need your help
                                          if(p.hasPotionEffect(PotionEffectType.SLOW_DIGGING)) {
                                            p.removePotionEffect(PotionEffectType.SLOW_DIGGING);
                                        }
                                      }
                                     
                                  }
                                  break;
                            }
                         }
                      if(p.hasPotionEffect(PotionEffectType.SLOW_DIGGING) && !foundPlayer) {
                        p.removePotionEffect(PotionEffectType.SLOW_DIGGING);
                    }
                  }   
              }, temporaryBreakTime);
           
        }
    }
    
    Just so you don't have to read ALL of that code, here is just my code that I need help with:
    Code:
    public void blockBreakingStages(BlockDamageEvent event, CraftPlayer p, int a, int stage, Block block) {
            int temporaryBreakTime = ((Integer)configurableBreakTime.get(a) / 9);
            onLog.info(""+temporaryBreakTime);
           
            BukkitScheduler scheduler = mainPlugin.getServer().getScheduler();
              scheduler.scheduleSyncDelayedTask(mainPlugin, new Runnable() {
                  public void run() {
                      boolean foundPlayer = false;
                      for(int i = 0; i < playerMiningBlock.size(); i++) {
                          if(playerMiningBlock.get(i) == event.getPlayer() ) {
                              foundPlayer = true;
                                  if(blockBeingMined.get(i) == block) {
                                     
                                      onLog.info("It works, yes inded, please sand halp");
                                      PacketPlayOutBlockBreakAnimation packet = new PacketPlayOutBlockBreakAnimation(event.getPlayer().getEntityId(), new BlockPosition(event.getBlock().getX(), event.getBlock().getY(), event.getBlock().getZ()), stage);
                                      SendPacket(p, packet);
                                      if(stage < 9) {
                                          blockBreakingStages(event, p, a, stage + 1, block);
                                          onLog.info("WHY");
                                      } else {
                                          PacketPlayInBlockDig packetBreak = new PacketPlayInBlockDig();
                                          mainPlugin.getServer().getPluginManager().callEvent(new BlockBreakEvent((Block) event.getBlock(), event.getPlayer()));
                                          event.getBlock().breakNaturally(event.getPlayer().getItemInHand());
                                          if(p.hasPotionEffect(PotionEffectType.SLOW_DIGGING)) {
                                            p.removePotionEffect(PotionEffectType.SLOW_DIGGING);
                                        }
                                      }
                                     
                                  }
                                  break;
                            }
                         }
                      if(p.hasPotionEffect(PotionEffectType.SLOW_DIGGING) && !foundPlayer) {
                        p.removePotionEffect(PotionEffectType.SLOW_DIGGING);
                    }
                  }   
              }, temporaryBreakTime);
           
        }
    
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
  2. Online

    KarimAKL

    I do not understand whether you are asking for help about detecting when the block has been broken or not?

    You can call Bukkit events using PluginManager#callEvent(Event).

    Also, I noticed that you are not following the Java naming conventions.
     
  3. Offline

    BaddCamden


    Yes, I want to be able to detect whether the player has broken the block, however I explicitly need that the block be broken as if the player did it. I have already assigned an event to be called whenever the block is broken for debugging and for some compatibility.

    Also when you say I am not following the Java Naming Conventions, I am assuming you mean that my variables are not named properly. I agree, however I will say that I have too specific scenarios for my variables to be any shorter. I usually try to make it at most 3 words per variable. Also when a variable is abbreviated, a majority of the time I don't know what it is, unless it is i (index/integer) or something universal like that
     

Share This Page