1.15.2 Efficiently remove spawners on chunk generate

Discussion in 'Spigot Plugin Development' started by lokka30, Feb 1, 2020.

  1. Hi! Is there a way to remove mob spawners when new chunks are generated?
    Using the ChunkPopulator for its unintended use does work, but consequently it spams the logs when exploring. I'm using PaperMC by the way.
    However, I can't simply remove all spawners from the world, as I use a custom spawner plugin SoulShards. I want players to craft their spawners rather than X-ray for them in dungeons.
    Cheers.

    Spam:
    Code (Text):
    [07:52:10 WARN]: Tried to load a DUMMY block entity @ BlockPosition{x=186, y=37, z=327} but found not block entity block Block{minecraft:diamond_ore} at location
    [07:52:10 WARN]: Tried to load a block entity for block Block{minecraft:diamond_ore} but failed at location BlockPosition{x=186, y=37, z=327}
     
    #1 lokka30, Feb 1, 2020
    Last edited: Feb 2, 2020
  2. md_5

    Administrator Developer

    Chunk Load -> IsNewChunk -> Get Tiles -> Remove
    You didn't think the 'spam' would be helpful to include?
     
  3. Personally I’d just listen to Spawnerspawnevent then whenever it tries to spawn a mob you can check and see if you would like to remove it and handle it then.

    Cancel the event and wait a tick then replace it with air.


    Sent from my iPhone using Tapatalk
     
  4. Thanks for your suggestion! I'll give it a shot now.

    Until second thought, nope. I'll include it soon with an edit to the original post in case users with the same issue can check if they have a similar warning in the logs.

    Thanks for your suggestion. As I failed to include in my original post, I still want to use spawners - they are crafted though, not found - thus, if I used this event, it would remove them. To add on,
    • it's a private plugin. I can't check on the event if it is in fact the custom spawner or a vanilla spawner.
    • if the player quickly torched the dungeon, mobs wouldn't spawn and would receive the spawner.
     
  5. So, this is my the old code:
    Code (Text):
    @EventHandler
        public void onChunkPopulate(final ChunkPopulateEvent e) {
            final Chunk chunk = e.getChunk();
            for(BlockState blockState : chunk.getTileEntities()) {
                if(blockState instanceof CreatureSpawner) {
                    blockState.getBlock().setType(Material.DIAMOND_ORE);
                }
            }
        }
    which produced this warning:
    Code (Text):
    [07:52:10 WARN]: Tried to load a DUMMY block entity @ BlockPosition{x=186, y=37, z=327} but found not block entity block Block{minecraft:diamond_ore} at location
    [07:52:10 WARN]: Tried to load a block entity for block Block{minecraft:diamond_ore} but failed at location BlockPosition{x=186, y=37, z=327}
    This is the new code:

    Code (Text):
    @EventHandler
        public void onChunkLoad(final ChunkLoadEvent e) {
            if(e.isNewChunk()) {
                final BlockState[] tileEntities = e.getChunk().getTileEntities();
                for(BlockState tileEntity : tileEntities) {
                    if(tileEntity.getBlock().getType() == Material.SPAWNER) {
                        //remove it
                    }
                }
            }
        }
    How would I go about removing it without the same warning recurring, as I believe .setType(Material.AIR) would?
     
  6. md_5

    Administrator Developer

    I don't think the warning will show there, just setType air
     
  7. Unfortunately, it has the exact same issue as the old solution - it replaces the spawner, but with this message in console:
    Code (Text):
    [08:35:56 WARN]: Tried to load a DUMMY block entity @ BlockPosition{x=-484, y=13, z=915} but found not block entity block Block{minecraft:air} at location
    [08:35:56 WARN]: Tried to load a block entity for block Block{minecraft:air} but failed at location BlockPosition{x=-484, y=13, z=915}
     
    #7 lokka30, Feb 2, 2020
    Last edited: Feb 2, 2020
  8. I think that you should focus on the BlockType and NOT the BlockState.

    I have seen the BlockType changed succesfuly in the past during ChunkLoad.

    I am thinking that from what I have read, is that the BlockState a transient object and is highly unlikely to be available (or constant) at the time of generation.
     
  9. I'll look into this. Thanks for your reply.

    Edit: @Goldentoenail I'm not familiar with chunks - please could you guide me in the right direction?
    Here's my current code:
    Code (Text):
    @EventHandler
        public void onChunkLoad(final ChunkLoadEvent e) {
            if(e.isNewChunk()) {
                for(BlockState tileEntity : e.getChunk().getTileEntities()) {
                    if(tileEntity.getBlock().getType() == Material.SPAWNER) {
                        final Location location = tileEntity.getLocation();
                        tileEntity.getBlock().setType(Material.AIR);
                       
                        Creeper creeper = (Creeper) location.getWorld().spawnEntity(location, EntityType.CREEPER);
                        creeper.setPowered(true);
                    }
                }
            }
        }
     
    #9 lokka30, Feb 2, 2020
    Last edited: Feb 2, 2020
  10. WTH
    Have you never heard of 'logical sequencing'?
    An action cannot be performed before a prevoius action has completed !

    The ChunkLoad process cannot predict what happens afterward!
    You cannot use it to find out if some mob has spawned or not, because it is a pre-condition (it is all new) before any spawn event.
     
  11. md_5

    Administrator Developer

    That's a bug and you should report it
     
    • Agree Agree x 1
  12. Ah, this is where I found my old solution.

    Alright, will do. I'm using PaperMC, I will check now if it is also a Spigot bug.

    If I can't do anything on ChunkLoad, how else am I meant to solve this issue?
    I'm not trying to check if a mob spawned - I am spawning a charged creeper as there isn't anything defending the loot. The mob spawn has nothing to do with the issue, and I probably should've left that out of the code.
     
  13. Can confirm this error happens on both Spigot and PaperMC.
    Reported the bug here. Note that the Spigot version is 27 versions behind and I no longer have BuildTools installed on my computer as I switched to a fork.
    @HexedHero, by any chance, do you have SpawnerRemover installed on your server? If not, have you found a solution to it?
     
    #14 lokka30, Feb 2, 2020
    Last edited: Feb 2, 2020
  14. This message will print from Chunk.java.
    We need to remove "DUMMY" id contain as NBTTagCompound when set Material.SPAWNER to any other type (such as Material.AIR).
    Or just comment out this warn...

    Code (Java):
    @Nullable
    private TileEntity a(BlockPosition blockposition, NBTTagCompound nbttagcompound) {
        TileEntity tileentity;

        if ("DUMMY".equals(nbttagcompound.getString("id"))) {
            Block block = this.getType(blockposition).getBlock();

            if (block instanceof ITileEntity) {
                tileentity = ((ITileEntity) block).createTile(this.world);
            } else {
                tileentity = null;
                Chunk.LOGGER.warn("Tried to load a DUMMY block entity @ {} but found not block entity block {} at location", blockposition, this.getType(blockposition));
            }
        } else {
            tileentity = TileEntity.create(nbttagcompound);
        }

        if (tileentity != null) {
            tileentity.setLocation(this.world, blockposition);
            this.a(tileentity);
        } else {
            Chunk.LOGGER.warn("Tried to load a block entity for block {} but failed at location {}", this.getType(blockposition), blockposition);
        }

        return tileentity;
    }
     
  15. If a proper way to change the material of blocks which happen to be tile entities is implemented then the warnings can stay (and they probably should) ;) Thanks for the observation.