1.8.8 Protected blocks from TNT

Discussion in 'Spigot Plugin Development' started by Kriiista, Oct 16, 2021.

  1. Hello, i'm developing a 1.8 bedwars plugin.

    I'm trying to make so glass blocks don't get damages from TNT.
    This is what i coded:
    Code (Java):
    @EventHandler
        public void onEntityExplode(EntityExplodeEvent event) {
            if (event.getEntity().getType() == EntityType.PRIMED_TNT) {
                if (this.plugin.getMatchManager().getSpawnedEntities().containsKey(event.getEntity())) {
                    UserData source = this.plugin.getMatchManager().getSpawnedEntities().get(event.getEntity());
                    Match match = this.plugin.getMatchManager().getMatch(source);
                    if (match != null) {
                        List<Block> destroyed = event.blockList();
                        destroyed.removeIf(block -> !match.getPlacedBlockLocations().contains(block.getLocation()));
                        destroyed.removeIf(block -> block.getType() == Material.STAINED_GLASS);
                    } else {
                        event.setCancelled(true);
                    }
                    this.plugin.getMatchManager().getSpawnedEntities().remove(event.getEntity());
                }
            }
        }
    It's working good but the problem is, blocks that are under the glass (that should be protected) are still getting damages. Here are some screenshots.

    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]

    Looks like I'm not using the correct code
     
  2. You could remove blocks in the list if they have glass between them and the TNT, but I bet there's a better solution.
     
  3. How can i check if there's glass between ?
     
  4. I don't think that's what I'm looking for. You're showing me how to edit the block resistance but that's not what I'm trying to do, as byteful said, i think i must find a way to check if there's a glass between the tnt and the block
     
  5. Well there are many ways, but the first that came to my mind would be to run a ray trace between the TNT and the block and see if the ray trace collides with a glass block.
     
    • Agree Agree x 1
  6. oof that's beyond my skills
     
  7. What @byteful recommends is probably your best bet, the only problem is that the ray tracing API included now in spigot is not available in <1.14 versions... so you'll need to search for some sort of ray tracing api that exists in 1.8 (or just update to recent versions to make your life easier!)
     
    • Informative Informative x 1
  8. You can use the BlockIterator class to perform a simple raytrace for a direct path.

    Another (heavier) method is to make a recursive method that looks for an opening in a ~3 block radius
     
    • Like Like x 1
  9. any examples please ?
     
  10. Code (Java):
    Vector tnt = tntLocation.toVector().clone();
    Vector block = blockLocation.toVector().clone();

    Vector diff = tnt.subtract(block).normalize();

    BlockIterator iterator = new BlockIterator(world, tnt, diff, 0.0d, tnt.distance(block));

    while(iterator.hasNext()) {
      Block possiblyGlassBlock = iterator.next();
      // check if glass and do your thing
    }
     
  11. Interesting, never knew this existed!
     
  12. I tried the code:

    Code (Java):
        @EventHandler
        public void onEntityExplode(EntityExplodeEvent event) {
            if (event.getEntity().getType() == EntityType.PRIMED_TNT) {
                List<Block> destroyed = event.blockList();
                List<Block> tocancel = new ArrayList<>();

                Iterator<Block> exploded = destroyed.iterator();
                while (exploded.hasNext()) {
                    boolean glass = false;
                    Vector tnt = event.getEntity().getLocation().toVector().clone();
                    Vector block = exploded.next().getLocation().toVector().clone();

                    Vector diff = tnt.subtract(block).normalize();

                    BlockIterator iterator = new BlockIterator(Bukkit.getWorld("world"), tnt, diff, 0.0d, (int) tnt.distance(block));

                    while(iterator.hasNext()) {
                        Block possiblyGlassBlock = iterator.next();
                        // check if glass and do your thing
                        if (possiblyGlassBlock.getType() == Material.STAINED_GLASS) {
                            glass = true;
                            break;
                        }
                    }
                    if (glass) {
                        tocancel.add(exploded.next());
                    }
                }
                tocancel.forEach(destroyed::remove);
                destroyed.removeIf(block -> block.getType() == Material.STAINED_GLASS);
            }
        }
    There's several problem. The first one is that the TNT for some reasons, damages the blocks 2s after it exploded.
    The second one is that it doesn't work :p

    [​IMG]
    [​IMG]
    [​IMG]
     
  13. I think the delay is due to server lag

    [​IMG]
     
  14. Ok i tried some stuff, it's not very stable. Some blocks get protected and some still get explode. to fix your code @byteful i changed the BlockIterator. And depending on the tnt position, it makes the server TPS drop.

    here's the code:
    Code (Java):
    @EventHandler
        public void onEntityExplode(EntityExplodeEvent event) {
            if (event.getEntity().getType() == EntityType.PRIMED_TNT) {
                List<Block> destroyed = event.blockList();
                List<Block> tocancel = new ArrayList<>();
                destroyed.removeIf(block -> block.getType() == Material.STAINED_GLASS);
                for (Block value : destroyed) {
                    boolean glass = false;
                    for (Block blocks : plugin.getMatchManager().getBlocksTo(event.getEntity().getLocation(), value.getLocation())) {
                        if (blocks.getType() == Material.STAINED_GLASS) {
                            glass = true;
                            break;
                        }
                    }
                    if (glass) {
                        tocancel.add(value);
                    }
                }
                tocancel.forEach(destroyed::remove);
            }
        }
    Code (Java):
    public List<Block> getBlocksTo(Location startLoc, Location endLoc) {
            Vector tnt = startLoc.toVector().clone();
            Vector block = endLoc.toVector().clone();
            Vector diff = tnt.subtract(block).normalize();
            List<Block> b = new ArrayList<>();
            BlockIterator BI = new BlockIterator(endLoc.getWorld(), block, diff, 0.0d, (int) startLoc.distance(endLoc));
            while(BI.hasNext()){
                Block blocks = BI.next();
                if (blocks.getType() != Material.AIR) {
                    b.add(blocks);
                }
            }
            return b;
        }
    [​IMG]
    BLOCKS ARE PROTECTED
    [​IMG]
    [​IMG]
    ONE BLOCK IS PROTECTED IDK WHY
    [​IMG]
    [​IMG]
    BLOCKS ARE PROTECTED
    [​IMG]
    [​IMG]
    HERE THE SERVER TPS DROPS
     
  15. Crazy idea here, but what if you clear the block list first, then run the block iterator & stuff asynchronous, and then set the blocks to what they should be after that synchronously.
     
    #16 byteful, Oct 17, 2021
    Last edited: Oct 17, 2021
    • Agree Agree x 1
  16. Doesn't work.

    [​IMG]

    It clears the blockList so no blocks get destroyed

    [​IMG]

    But the BlockIterator returns empty block list
     
  17. You are returning the list before you populate it since the task is async and isn’t executed at that moment. You might want to look into concurrent programming.