Some blocks won't update after changing them

Discussion in 'Plugin Development' started by Leon167, Apr 1, 2018.

Thread Status:
Not open for further replies.
  1. Offline

    Leon167

    Hey, I'm currently developing a plugin that changes the blocks of a 42*42 area. But somehow, some of the blocks wont update. And its the same area that won't change over and over again until i restart the server. After that the 'unchangeable' area is in different place with a different size. Sommetimes it works perfectly without an unchangeable area. I'm using the following code:

    Code:
    public void placeFloor() {
            if (this.bp.getNmsBlock() == null) {
                for (int x = 0; x < size.getBlockX(); x++) {
                    for (int z = 0; z < size.getBlockZ(); z++) {
                        World world = a.getWorld();
                        world.getBlockAt(a.getBlockX() + x, a.getBlockY(), a.getBlockZ() + z).setTypeId(cc.getBlock(new Vector(x, 0, z)).getId());
                        world.getBlockAt(a.getBlockX() + x, a.getBlockY(), a.getBlockZ() + z).setData((byte) cc.getBlock(new Vector(x, 0, z)).getData());
                    }
                }
            }
            else
            {
                for (int x = 0; x < size.getBlockX(); x++) {
                    for (int z = 0; z < size.getBlockZ(); z++) {
                        BaseBlock block = cc.getBlock(new Vector(x, 0, z));
                        World world = a.getWorld();
                        try {
                            this.bp.getNmsBlock().set(world.getBlockAt(a.getBlockX() + x, a.getBlockY(), a.getBlockZ() + z), block.getId(), block.getData());
                        } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException | InstantiationException | NoSuchFieldException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    The 2nd part is my try to change the blocks via nms. But i am having the same issue there...

    NMS (open)

    Code:
    public class NMSBlock {
    
        private Class<?> CraftWorld, World, BlockPosition, Block, IBlockData, Chunk, CraftChunk, CraftPlayer, PacketPlayOutMapChunk, EntityPlayer, PlayerConnection, Packet;
        private Method getHandle, setTypeIdAndData, update;
        private String version;
        private PacketMapChunk pmc;
    
        public NMSBlock() throws NoSuchMethodException, ClassNotFoundException {
            String packageName = Bukkit.getServer().getClass().getPackage().getName();
            this.version = packageName.substring(packageName.lastIndexOf(".") + 1);
            setup();
        }
    
        private void setup() throws NoSuchMethodException, ClassNotFoundException {
            CraftWorld = getNMSClass("org.bukkit.craftbukkit.%s.CraftWorld");
            World = getNMSClass("net.minecraft.server.%s.World");
            getHandle = CraftWorld.getDeclaredMethod("getHandle");
            BlockPosition = getNMSClass("net.minecraft.server.%s.BlockPosition");
            Block = getNMSClass("net.minecraft.server.%s.Block");
            IBlockData = getNMSClass("net.minecraft.server.%s.IBlockData");
            setTypeIdAndData = World.getDeclaredMethod("setTypeAndData", BlockPosition, IBlockData, int.class);
            Chunk = getNMSClass("net.minecraft.server.%s.Chunk");
            update = Chunk.getDeclaredMethod("a", BlockPosition, IBlockData);
            CraftChunk = getNMSClass("org.bukkit.craftbukkit.%s.CraftChunk");
            CraftPlayer = getNMSClass("org.bukkit.craftbukkit.%s.entity.CraftPlayer");
            PacketPlayOutMapChunk = getNMSClass("net.minecraft.server.%s.PacketPlayOutMapChunk");
            EntityPlayer = getNMSClass("net.minecraft.server.%s.EntityPlayer");
            PlayerConnection = getNMSClass("net.minecraft.server.%s.PlayerConnection");
            Packet = getNMSClass("net.minecraft.server.%s.Packet");
        }
    
        private Class<?> getNMSClass(String nmsClass) throws ClassNotFoundException {
            return Class.forName(nmsClass.replace("%s", version));
        }
    
        public void set(Block b, int typeId, int data) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException, NoSuchFieldException {
            Object craftWorld = getHandle.invoke(CraftWorld.cast(b.getWorld()));
            int combined = typeId + (data << 12);
            Object position = BlockPosition.getConstructor(int.class, int.class, int.class).newInstance(b.getX(), b.getY(), b.getZ());
            Object block = Block.getDeclaredMethod("getByCombinedId", int.class).invoke(null, combined);
    
            setTypeIdAndData.invoke(craftWorld, position, block, 0);
            update.invoke(World.getMethod("getChunkAt", int.class, int.class).invoke(World.cast(craftWorld), b.getX() >> 4, b.getZ() >> 4), position, block);
            if(pmc == null || !pmc.getbChunk().equals(b.getChunk()))
            {
                pmc = new PacketMapChunk(b.getChunk());
                pmc.refreshChunk();
            }
    
        }
    
        public class PacketMapChunk {
    
            private final Object chunk;
            private org.bukkit.Chunk bChunk;
            private int x, z;
    
            /**
             * Creates a PacketMapChunk.
             *
             * @param world The chunk's world.
             * @param x The chunk's X.
             * @param z The chunk's Z.
             */
    
            public PacketMapChunk(final org.bukkit.World world, final int x, final int z) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
                this(world.getChunkAt(x, z));
                this.x = x;
                this.z = z;
            }
    
            /**
             * Creates a PacketMapChunk.
             *
             * @param chunk The chunk.
             */
    
            public PacketMapChunk(final org.bukkit.Chunk chunk) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
                this.bChunk = chunk;
                this.chunk = CraftChunk.getDeclaredMethod("getHandle").invoke(CraftChunk.cast(chunk));
                //this.chunk = ((CraftChunk)chunk).getHandle();
            }
    
            /**
             * Sends this packet to a player.
             * <br>You still need to refresh it manually with <code>world.refreshChunk(...)</code>.
             *
             * @param player The player.
             */
            public void send(final Player player) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, InstantiationException {
                PlayerConnection.getDeclaredMethod("sendPacket", Packet)
                        .invoke(EntityPlayer.getField("playerConnection")
                                .get(CraftPlayer.getDeclaredMethod("getHandle")
                                        .invoke(CraftPlayer.cast(player))), PacketPlayOutMapChunk.getConstructor(Chunk, int.class).newInstance(Chunk.cast(chunk), 20));
                //((CraftPlayer)player).getHandle().playerConnection.sendPacket(new PacketPlayOutMapChunk(chunk, true, 20));
            }
    
            public void refreshChunk() throws InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException, IllegalAccessException {
                refreshChunk(this.bChunk);
            }
    
            /**
             * Refresh a chunk.
             *
             * @param chunk The chunk.
             */
    
            public void refreshChunk(final org.bukkit.Chunk chunk) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, InstantiationException {
                //refreshChunk(Chunk.getDeclaredMethod("getWorld").invoke(chunk), (int)Chunk.getDeclaredMethod("getX").invoke(chunk), (int)Chunk.getDeclaredMethod("getY").invoke(chunk));
                refreshChunk(chunk.getWorld(), chunk.getX(), chunk.getZ());
            }
    
            /**
             * Wrapper for <code>world.refreshChunk(...)</code>
             *
             * @param world The world.
             * @param x The chunk's X.
             * @param z The chunk's Z.
             */
    
            public void refreshChunk(final org.bukkit.World world, final int x, final int z) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, InstantiationException {
                final Collection<? extends Player> players = Bukkit.getOnlinePlayers();
                refreshChunk(world, x, z, players.toArray(new Player[players.size()]));
            }
    
            /**
             * Refresh a chunk for the selected players.
             *
             * @param world The chunk's world.
             * @param x The chunk's X.
             * @param z The chunk's Z.
             * @param players The players.
             */
    
            public void refreshChunk(final org.bukkit.World world, final int x, final int z, final Player... players) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, InstantiationException {
                this.x = x;
                this.z = z;
                for(Player player : players) {
                    this.send(player);
                }
                world.refreshChunk(this.x, this.z);
            }
    
            public org.bukkit.Chunk getbChunk() {
                return bChunk;
            }
    
            @Override
            public boolean equals(Object pmc) {
                return pmc instanceof PacketMapChunk && this.bChunk.equals(((PacketMapChunk) pmc).getbChunk());
            }
        }
    
    
    }
     
  2. You’re trying to do some complicated stuff for a simple task. You don’t need to set any NMS data unless you want to do something Bukkit doesn’t provide means of doing (example: edit a mob’s AI goals).

    You can just loop through the min and max X Y and Z of where you need to set, and use those variables as the coordinates.

    Code:
    //Sets all blocks between x1, y1, z1 and x2, y2, z2 to stone
    
    for (int x = platform.x1; x <= platform.x2; x++) {
    for (int y = platform.y1; y <= platform.y2; y++) {
    for (int z = platform.z1; z <= platform.z2; z++) {
        world.getBlockAt(x, y, z).setType(Material.STONE);
    }}}
    I would also highly suggest holding reference to objects. If you create a Block variable, you’re only making a link to an existing block, not creating a new object (that is done when you use the new keyword, such as new HashMap). Try holding reference to a block or world rather than getting it each time you need it.
     
    Last edited: Apr 6, 2018
Thread Status:
Not open for further replies.

Share This Page