Solved Make piston move

Discussion in 'Spigot Plugin Development' started by OkDexter12, Feb 14, 2020.

  1. Is there anyway to make a piston extend naturally with code? I tried setting making it's blockdata of setExtended to true, but it just make the piston head part disappear and the block in front doesn't get pushed at all.

    Any help would be appreciated, thanks.
     
  2. Thats because a Piston is not Powerable but the BlockData is, read the docs
     

  3. I'm casting the piston block's blockdata to the blockdata type of powerable not the actual block.

    Code (Text):
    Block b = //never null;
    BlockData bd = b.getBlockData();

    if(bd instanceof Piston){
          Powerable piston = (Powerable) bd;
          piston.setPowered(true);
          b.setBlockData(piston);
    }
     
  4. Ah i see, then im not sure :B
     
  5. drives_a_ford

    Moderator

  6. Setting the piston to extended only removed the piston head from the piston block texture-wise. Doesn't actually extend it sadly.
     
  7. drives_a_ford

    Moderator

    It looks like you might need to resort to NMS for this to work. It looks like you'll need to call the private method BlockPiston#a:
    private boolean a(World world, BlockPosition blockposition, EnumDirection enumdirection, boolean flag).
    The public method BlockPiston#a (with i=0)
    public boolean a(IBlockData iblockdata, World world, BlockPosition blockposition, int i, int j)
    should do that for you.

    You should be able to get the IBlockData from NMS World#getType from the BlockPosition.
     
    #9 drives_a_ford, Feb 14, 2020
    Last edited: Feb 14, 2020
    • Useful Useful x 1
  8. Alright I think I solved it with your help so thanks. For anyone who comes with the same problem in the future here's my solution:

    Code (Text):
    public static boolean movePiston(Block piston) throws Exception {
            BlockData bd =  piston.getBlockData();
            Piston redstone = (Piston) bd;
            boolean extended = redstone.isExtended();
         
            BlockFace bf = ((Directional) bd).getFacing();
         
         
            Object nmsWorld = (main.getNmsClass("CraftWorld", true).cast(piston.getWorld())).getClass().getMethod("getHandle").invoke((main.getNmsClass("CraftWorld", true).cast(piston.getWorld())));
            Object pistonPosition = main.getNmsClass("BlockPosition", false).getConstructor(int.class, int.class, int.class).newInstance(piston.getX(), piston.getY(), piston.getZ());
            Object nmsBlockData = nmsWorld.getClass().getMethod("getType", pistonPosition.getClass()).invoke(nmsWorld, pistonPosition);
            Object nmsPiston = main.getNmsClass("BlockPiston", false).cast(nmsBlockData.getClass().getMethod("getBlock").invoke(nmsBlockData));
         
            try {
                Method method = nmsPiston.getClass().getDeclaredMethod("a", main.getNmsClass("World", false) , main.getNmsClass("BlockPosition", false) , main.getNmsClass("EnumDirection", false) , boolean.class);
                method.setAccessible(true);
                if(extended == true) {
                    redstone.setExtended(false);
                    piston.setBlockData(redstone);
                }
                redstone.setExtended(true);
                piston.setBlockData(redstone);
                boolean bold = (boolean) method.invoke(nmsPiston, nmsWorld, pistonPosition, interchangeDirections(bf),  !extended);
                if(!bold) {
                    redstone.setExtended(false);
                    piston.setBlockData(redstone);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
         
            return extended;
        }
     
        public static Object interchangeDirections(BlockFace bf) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException{
            Class enumDirection = (Class) main.getNmsClass("EnumDirection", false);
            if(bf == BlockFace.DOWN) {
                return Enum.valueOf(enumDirection, "DOWN");
            }
            else if(bf == BlockFace.UP) {
                return Enum.valueOf(enumDirection, "UP");
            }
            else if(bf == BlockFace.EAST) {
                return Enum.valueOf(enumDirection, "EAST");
            }
            else if(bf == BlockFace.NORTH) {
                return Enum.valueOf(enumDirection, "NORTH");
            }
            else if(bf == BlockFace.SOUTH) {
                return Enum.valueOf(enumDirection, "SOUTH");
            }
            else if(bf == BlockFace.WEST) {
                return Enum.valueOf(enumDirection, "WEST");
            }
            return null;
        }

    public static Class<?> getNmsClass(String nmsClassName, boolean craftbukkit) throws ClassNotFoundException {
            String start = "net.minecraft.server.";
            if(craftbukkit) {
                start = "org.bukkit.craftbukkit.";
            }
            return Class.forName(start
                    + Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3] + "."
                    + nmsClassName);
        }

    I'm pretty sure it could be improved since I suck at using reflection and i'm also not too good with NMS, but it was the best I could muster. Only downside I found was it retracts the piston after extending it due to no power source being nearby. I'm sure there was a way to fix this which I missed, but I didn't need it for what I was doing.

    One thing that could definitely be added is a check to find the method name throughout various versions, since nms method names change during updates. Could use return type, visibility, and parameters to verify correct method.
     
    #10 OkDexter12, Feb 18, 2020
    Last edited: Feb 18, 2020