[SOLVED] Sending chunk updates to clients

Discussion in 'Plugin Development' started by micomico, Apr 4, 2012.

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

    micomico

    Hello there.

    I'm making a new bukkit plugin to allow players to change the chunk biome in-game.

    I made the plugin and it's doing what it's supposed to. The current chunk biome changes to the one indicated in the command.

    I've a problem however, hence this post. The chunk biome only changes in the client after reconnecting to the server. How do I send these changes to client?

    I've seen sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) in Player class, but don't know what to put in byte[] data.

    Can anybody help me here? Thanks!

    You can see the current code below:
    Show Spoiler
    Code:
    package com.gmail.azmicomico.BiomeChanger;
     
    import java.util.logging.Logger;
     
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.block.Biome;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
     
    public class BiomeChanger extends JavaPlugin {
        Logger log;
     
        public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
            Player player = null;
            if (sender instanceof Player)
                player = (Player) sender;
     
            if(cmd.getName().equalsIgnoreCase("biomechange")) {
                if (player == null) {
                    sender.sendMessage("The biomechange command can only be run by a player");
                    return true;
                }
     
                if (args.length != 1) {
                    sender.sendMessage("Incorrect arguments!");
                    return false;
                }
     
                Biome[] existingBiomes = Biome.values();
                Biome targetBiome = Biome.PLAINS;
               
                try {
                    int candidateBiome = Integer.parseInt(args[0]);
                    if (candidateBiome >= 0 && candidateBiome < existingBiomes.length)
                        targetBiome = existingBiomes[candidateBiome];
                }
                catch (NumberFormatException e) {
                    String candidateBiomeStr = args[0].toUpperCase();
                    targetBiome = Biome.valueOf(candidateBiomeStr);
                }
                catch (IllegalArgumentException e) {
                    sender.sendMessage("Invalid biome!");
                    return false;
                }
     
                Location playerLocation = player.getLocation();
                World playerWorld = player.getWorld();
               
     
                int playerX = playerLocation.getBlockX();
                int playerZ = playerLocation.getBlockZ();
     
                int chunkX = playerX - ((playerX % 16 + 16) % 16);
                int chunkZ = playerZ - ((playerZ % 16 + 16) % 16);
     
                sender.sendMessage("Player at x:" + playerX + " z:" + playerZ);
                sender.sendMessage("Mod x:" + ((playerX % 16 + 16) % 16) + " z:" + ((playerZ % 16 + 16) % 16));
                sender.sendMessage("Chunk at x:" + chunkX +" z:" + chunkZ);
               
                for (int xPos = chunkX ; xPos < chunkX + 16 ; xPos++)
                    for (int zPos = chunkZ ; zPos < chunkZ + 16 ; zPos++)
                        playerWorld.setBiome(xPos, zPos, targetBiome);
               
                sender.sendMessage("Biome changed to "+targetBiome.toString());
                return true;
            }
     
            return false;
        }
     
        public void onDisable() {
            log.info("BiomeChanger has been disabled.");
        }
     
        public void onEnable() {
            log = this.getLogger();
            log.info("BiomeChanger has been enabled!");
        }
    }
     
  2. Offline

    bergerkiller

    micomico do NOT use the sendChunkChange, it is terribly unstable and cause clients to lose connection.

    Here, use this (reference CraftBukkit):
    Code:
    int diffx, diffz;
    int view = Bukkit.getServer().getViewDistance() << 4;
    for (Chunk chunk : changedChunks) {
        net.minecraft.server.World world = ((CraftChunk) chunk).getHandle().world;
        for (EntityPlayer ep : (List<EntityPlayer>) world.players) {
            diffx = Math.abs(ep.locX - chunk.getX() << 4);
            diffz = Math.abs(ep.locZ - chunk.getZ() << 4);
            if (diffx <= view && diffz <= view) {
                ep.chunkCoordIntPairQueue.add(new ChunkCoordIntPair(chunk.getX(), chunk.getZ()));
            }
        }
    }
    Fairly complicated, so hopefully you'll get around it...
     
    J3H1 likes this.
  3. Offline

    micomico

    Thanks for your quick reply.

    I had to change your code a bit, since I only had one chunk to update. A few casts were needed and I also had to include the whole craftbukkit.jar as a library in eclipse to be able to access the some of the classes. The bukkit.jar (API) doesn't include some of them.

    It works perfectly. Thanks a lot!

    The changed code, for reference:
    Show Spoiler
    Code:
    package com.gmail.azmicomico.BiomeChanger;
     
    import java.util.List;
    import java.util.logging.Logger;
     
    import net.minecraft.server.ChunkCoordIntPair;
    import net.minecraft.server.EntityPlayer;
     
    import org.bukkit.Bukkit;
    import org.bukkit.Chunk;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.block.Biome;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.craftbukkit.CraftChunk;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
     
    public class BiomeChanger extends JavaPlugin {
        Logger log;
     
        @SuppressWarnings("unchecked")
        public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
            Player player = null;
            if (sender instanceof Player)
                player = (Player) sender;
     
            if(cmd.getName().equalsIgnoreCase("biomechange")) {
                if (player == null) {
                    sender.sendMessage("The biomechange command can only be run by a player");
                    return true;
                }
     
                if (args.length != 1) {
                    sender.sendMessage("Incorrect arguments!");
                    return false;
                }
     
                Biome[] existingBiomes = Biome.values();
                Biome targetBiome = Biome.PLAINS;
             
                try {
                    int candidateBiome = Integer.parseInt(args[0]);
                    if (candidateBiome >= 0 && candidateBiome < existingBiomes.length)
                        targetBiome = existingBiomes[candidateBiome];
                }
                catch (NumberFormatException e) {
                    String candidateBiomeStr = args[0].toUpperCase();
                    targetBiome = Biome.valueOf(candidateBiomeStr);
                }
                catch (IllegalArgumentException e) {
                    sender.sendMessage("Invalid biome!");
                    return false;
                }
     
                Location playerLocation = player.getLocation();
                World playerWorld = player.getWorld();
     
                int playerX = playerLocation.getBlockX();
                int playerZ = playerLocation.getBlockZ();
     
                int chunkX = playerX - ((playerX % 16 + 16) % 16);
                int chunkZ = playerZ - ((playerZ % 16 + 16) % 16);
     
                sender.sendMessage("Player at x:" + playerX + " z:" + playerZ);
                sender.sendMessage("Mod x:" + ((playerX % 16 + 16) % 16) + " z:" + ((playerZ % 16 + 16) % 16));
                sender.sendMessage("Chunk at x:" + chunkX +" z:" + chunkZ);
             
                for (int xPos = chunkX ; xPos < chunkX + 16 ; xPos++)
                    for (int zPos = chunkZ ; zPos < chunkZ + 16 ; zPos++)
                        playerWorld.setBiome(xPos, zPos, targetBiome);
             
                Chunk currentChunk = playerWorld.getChunkAt(playerLocation);
             
                int diffX, diffZ;
                int viewDistance = Bukkit.getServer().getViewDistance() << 4;
                net.minecraft.server.World mcWorld = ((CraftChunk) currentChunk).getHandle().world;
                for (EntityPlayer ep : (List<EntityPlayer>) mcWorld.players) {
                    diffX = (int) Math.abs(ep.locX - (currentChunk.getX() << 4));
                    diffZ = (int) Math.abs(ep.locZ - (currentChunk.getZ() << 4));
                    if (diffX <= viewDistance && diffZ <= viewDistance)
                        ep.chunkCoordIntPairQueue.add(new ChunkCoordIntPair(currentChunk.getX(), currentChunk.getZ()));
                }
             
                sender.sendMessage("Biome changed to "+targetBiome.toString());
                return true;
            }
     
            return false;
        }
     
        public void onDisable() {
            log.info("BiomeChanger has been disabled.");
        }
     
        public void onEnable() {
            log = this.getLogger();
            log.info("BiomeChanger has been enabled!");
        }
    }
     
    J3H1 likes this.
Thread Status:
Not open for further replies.

Share This Page