Solved Making a fix for my plugin if FallingSand lands on a block

Discussion in 'Spigot Plugin Development' started by devJordan, Dec 28, 2021.

Thread Status:
Not open for further replies.
  1. Explanation of what the plugin does and the relevant method
    Hey there! I am currently in the process of making a custom Envoy/Airdrop/SupplyDrop plugin, whichever term you prefer. Essentially it uses Entity#FallingBlock to make a barrel fall from the sky, then when it hits the ground it is turned into a barrel filled with items.

    There is quite a lot to the plugin, but this is the method that is relevant in the block being placed
    Code (Java):
        @EventHandler
        public void changeStateEvent(EntityChangeBlockEvent event) {
            if (!(event.getEntity() == airdrop)) return;
            event.setCancelled(true);
            Location loc = airdrop.getLocation();
            event.getBlock().setType(Material.BARREL);
            Directional direction = (Directional) event.getBlock().getState().getBlockData();
            direction.setFacing(BlockFace.UP);
            event.getBlock().setBlockData(direction);

            Barrel barrel = (Barrel) event.getBlock().getState();
            Inventory inv = barrel.getInventory();
            inv.addItem(new ItemStack(Material.STONE));

            loc.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, airdrop.getLocation(), 50, 2, 2, 2, 0.05);
            for (Player player : Bukkit.getOnlinePlayers()) {
                player.playSound(loc, Sound.ENTITY_GENERIC_EXPLODE, 4, 0.5F);
            }
        }
    The issue I am trying to address
    The intent of the plugin is for airdrops to spawn at random times in random locations, and when one spawns it will as well as its location will be broadcasted to the server. The issue however is the defined area is quite large and includes blocks such as slabs, torches, snow layers, and similar blocks that FallingBlock will not be able to place a block on (Exactly like when sand falls on a torch). So I am trying to handle that issue. I have a few ideas but don't know how to go about doing them or if there is a better way.

    My ideas
    A. I could see if the "event.getBlock().setType" fails to place the barrel and if it does I could add +1 to the y position and then place it (again I am not sure how I would go about doing this).

    B. When the airdrop first spawns in I could see what the nearest block below the airdrop (keeping in mind that the airdrop spawns at 255, so the nearest block won't exactly be right below it), and then I could either cancel that airdrop spawning and redo it until it gets a location that is safe, or I could again later in the code add +1 to the y and then set the block (again I am not sure how I would go about doing this).

    Any and all help is appreciated, I have not been able to get an answer in any communites I've asked so far!
     
  2. Oh thank you! I appreciate you addressing both of my ideas. I'm not exactly sure how setType works in this case, because I'm not super familiar with EntityChangeBlockEvent, but what I know is that in a normal case when a FallingBlock lands it places that block, just like sand falling. I think what setType is doing is setting the block that would have been placed had we not cancelled the event, this is so that we can get the block (because the methods for the event are quite limited) and then fill its contents. But when the FallingBlock falls on sand the block before we cancel the event wouldn't have been placed in the first place. And because of that we can't check what the old block type would be, because it would be the non existance barrel, so the old block type would always return a barrel.

    EDIT:
    As for the getHighestBlockAt, so close! I thought it was gonna work, unfortunatelly it doesn't detect snow layers or torches, snow layers probably being on of the bigger issues as the map this will be happening in, the theme is a frozen wasteland
     
    #3 devJordan, Dec 28, 2021
    Last edited: Dec 28, 2021
  3. Listen to ItemSpawnEvent. The falling block being destroyed will call that. If you get all nearby entities in a 1 block radius from that spawned item location and compare them to your falling block entity, you will find a match. From there you can proceed as normal.
     
  4. That's a great idea! I had always been deleting the dropped item because I didn't want it there (but of course at the end I can cancel ItemSpawnEvent instead). Question though, by the item an item spawns wouldn't the entity in a 1 block radius (that being the falling block) already be gone?
     
  5. No, the item spawning occurs in the same tick as the falling block being destroyed. Thus the falling block should still exist as an entity.
     
  6. You could get the block above the value returned from World#getHighestBlockAt() and check if it != AIR.
     
  7. Code (Java):
        @EventHandler
        public void unsafeLocation(ItemSpawnEvent event) {
            Entity airdropAsEntity = (Entity) airdrop;
            if (event.getEntity().getNearbyEntities(1,1,1) == airdropAsEntity) {
                System.out.println("Test");
            }
        }
    Didn't work, did I do something wrong here?
     
  8. That could work, but wouldn't work for torches if they weren't directly on the ground.
     
  9. Try using .equals() to compare the entities instead of ==. == checks that the two objects are stored in the same memory location, while .equals() checks the values within the object. Often == does not work as intended for nonprimitive types.
     
  10. #getNearbyEntities returns a List, obviously you will have to loop through it and compare each entry with your entity. Whether you use == or .equals probably doesn't matter in this case.
     
  11. Still a no go
    Code (Java):
        @EventHandler
        public void unsafeLocation(ItemSpawnEvent event) {
            Entity airdropAsEntity = (Entity) airdrop;
            for (Entity entity : event.getEntity().getNearbyEntities(1,1,1)) {
                if (entity.equals(airdropAsEntity)) {
                    System.out.println("True");
                }
            }
        }
     
  12. I would try comparing entity id’s. You can print out both of the entity id’s and see if they end up matching up and that could lead you somewhere.
     
  13. No sir :/
    Code (Text):
        @EventHandler
        public void unsafeLocation(ItemSpawnEvent event) {
            Entity airdropAsEntity = (Entity) airdrop;
            for (Entity entity : event.getEntity().getNearbyEntities(1,1,1)) {
                UUID itemEntityID = entity.getUniqueId();
                UUID airdropEntityID = entity.getUniqueId();
                if (itemEntityID.equals(airdropEntityID)) {
                    System.out.println("True");
                }
            }
        }
     
  14. My apologies. I was mistaken with that event being fired then. However, the alternative suggested by Dexuby still works.
     
  15. Unfortunately from what I understand checking the block at the time it’s being placed wouldn’t work because the block we’re referring to is the barrel block that would have been placed had we not cancelled the event which means the block.getType will always be barrel
     
  16. No, I meant the other alternative solution, of getting World#getHighestBlockAt. You'd check that when getting the location to spawn your falling block at.
     
  17. Ohhhh yeah, unfortunately it’s not foolproof because like I mentioned if there were something like a torch or somehow a floating lantern or sign that was off the ground then it wouldn’t work, which I guess could be solved with a few map modifications so I will look into this, if you or anyone else come up with any more solid solutions please do let me know
     
  18. Just check if the material at the highest point is solid/if you can build on it. https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html#isSolid() if not you could pick a different location or replace the block or place it on top of the block, whatever you want.
     
    • Agree Agree x 1
  19. To add on to Dexuby's post, if the highest block is not solid, you could try finding the next solid block below that one.
     
Thread Status:
Not open for further replies.