When to replace all ores

Discussion in 'Plugin Development' started by knokko, Aug 30, 2017.

Thread Status:
Not open for further replies.
  1. I am trying to make a plug-in which will make x-ray almost useless. The way I am trying to accomplish this is replacing all ores that are not next to air with stone after chunks are being generated, save the locations of all ores in custom files and place the ore back when a block next to the ore is broken.

    I made a method for replacing the ores, that method is: (sorry, but I can't find button for spoiler or code)

    Code:
    private void processChunk(Chunk chunk){
            List<HiddenBlock> ores = new ArrayList<HiddenBlock>(300);
            for(int cx = 0; cx < 16; cx++){
                for(int cy = 1; cy < 64; cy++){
                    for(int cz = 0; cz < 16; cz++){
                        Block block = chunk.getWorld().getBlockAt(cx + chunk.getX() * 16, cy, cz + chunk.getZ() * 16);
                        if(needsHide(block.getType()) && isHidden(block)){
                            ores.add(new HiddenBlock(chunk.getX() * 16 + cx, cy, chunk.getZ() * 16 + cz, block.getType()));
                            block.setType(Material.STONE);
                        }
                    }
                }
            }
            data.put(new ChunkLocation(chunk), new ChunkData(ores));
        }
    
    private boolean needsHide(Material t){
            return t == Material.COAL_ORE || t == Material.IRON_ORE || t == Material.LAPIS_ORE || t == Material.GOLD_ORE
                    || t == Material.REDSTONE_ORE || t == Material.DIAMOND_ORE || t == Material.EMERALD_ORE;
        }
    
    private boolean isHidden(Block block){
            if(block.getRelative(BlockFace.NORTH).getType() == Material.AIR)
                return false;
            if(block.getRelative(BlockFace.EAST).getType() == Material.AIR)
                return false;
            if(block.getRelative(BlockFace.SOUTH).getType() == Material.AIR)
                return false;
            if(block.getRelative(BlockFace.WEST).getType() == Material.AIR)
                return false;
            if(block.getRelative(BlockFace.UP).getType() == Material.AIR)
                return false;
            return block.getRelative(BlockFace.DOWN).getType() != Material.AIR;
        }
    
    I suppose these methods aren't very complicated.
    When I call this method on the right moment, it will replace all ores that are not hidden with stone. However, I can't find the right moment to call this method. (I can hardly believe I can't solve this myself...)

    I have tried to process the chunk in the ChunkPopulateEvent, because this should be called after chunk population. I have tried it calling the method directly and I have tried using the scheduler to call it after a delay which varies from 2 ticks to 200 ticks. I also tried creating my own chunk populator and registering it.
    All ways seemed to have the same effect: not ALL hidden ores were replaced.

    I am using the event like this:
    Code:
    @EventHandler
        public void onChunkPopulate(ChunkPopulateEvent event){
            /*
            final Chunk chunk = event.getChunk();
            Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
    
                public void run() {
                    processChunk(chunk);
                }
              
            }, 1);//TODO Some ores are being hidden, but not all?
            */
            processChunk(event.getChunk());
        }


    In order to help me with debugging, I registered a test command and used it many times during my tests.
    I was using an x-ray resource pack for the tests.
    The execute method for this command is:
    Code:
    @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args){
            if(args.length == 1 && sender instanceof Player){
                Chunk chunk = ((Player)sender).getLocation().getChunk();
                if(args[0].equals("countores")){
                    countOres(sender, chunk);
                }
                else if(args[0].equals("process")){
                    processChunk(chunk);
                    sender.sendMessage("Processed your current chunk.");
                }
                else if(args[0].equals("loadedchunks")){
                    sender.sendMessage("Amount of loaded chunk data is " + data.size());
                }
                else if(args[0].equals("coords")){
                    sender.sendMessage("The chunk coordinates are (" + chunk.getX() + "," + chunk.getZ() + "");
                }
                else if(args[0].equals("restore")){
                    ChunkData cd = getChunkData(chunk);
                    for(HiddenBlock hb : cd.blocks)
                        chunk.getWorld().getBlockAt(hb.x, hb.y, hb.z).setType(hb.type);
                    sender.sendMessage("Restored " + cd.blocks.size() + " hidden ores.");
                    cd.blocks.clear();
                }
            }
            if(args.length == 3){
                if(args[0].equals("countores")){
                    try {
                        int chunkX = Integer.decode(args[1]);
                        int chunkZ = Integer.decode(args[2]);
                        World world = Bukkit.getWorld("world");
                        Chunk chunk = world.getChunkAt(chunkX, chunkZ);
            
                        countOres(sender, chunk);
                    } catch(NumberFormatException nfe){
                        sender.sendMessage(nfe.getLocalizedMessage());
                    }
                }
            }
            return true;
        }
    
    
    I used the countores part for making sure the ores are also in the world on server side. I used the process command to test the process method after chunk population. I used the restore command to see how many ores were replaced.

    My results were pretty interesting:
    -According to x-ray, some ores are always visible, and some are only visible when I break the block next to it.
    -According to the process command, not all ores that should have been replaced after chunk initialisation were actually replaced.
    -According to the restore command, some ores were really replaced.

    I just can't find out why this doesn't work. Is there some kind of world gen secret I am missing?
    Or am I doing something entirely wrong?
     
  2. Offline

    Zombie_Striker

    @knokko
    If you're only writing this to get the result, why not use Orebfusticator:
    <Edit by Moderator: Redacted not allowed paid resource url>

    The issue is that you are checking the blocks synchronously. This means that when your plugin stops to check if there are ores, the whole server stops. What you need to do is create a BukkitRunnable, run it asynchronously, and do all the ore checks in there. Once you find an ore, however, you will need to create a synchronous bukkitrunnable (since blocks can't be set asynchronously) to set the ore to stone.
     
    Last edited by a moderator: Feb 9, 2021
Thread Status:
Not open for further replies.

Share This Page