Solved how to make a fake explosion that only damages enemies

Discussion in 'Spigot Plugin Development' started by mason-walker, Jun 27, 2021.

Thread Status:
Not open for further replies.
  1. I have a right click ability on an item that creates an explosion at the players location, but I want to make a fake explosion, that can do a custom amount of damage to only non-players, and not blocks destroyed, how can I do this?
     
  2. You have two options:
    1 - Spawn explosion effect and sound, then listen for nearby entities in a range of 4-5 blocks, damaging whatever you want
    2 - Spawn a TNT that will explode instantly, then listen for EntityExplodeEvent and EntityDamageEvent, in the EntityExplodeEvent, check if the entity is a TNT, then get all the nearby entities and add whatever entity you want to a list that your EntityDamageEvent can listen, after that, remove the blocks you don't want to be removed from the explosion, modifying EntityExplodeEvent#blockList

    First method:
    Code (Java):
    World world = Bukkit.getServer().getWorlds().get(0);
    Location location = null /*the explosion location*/ ;

    world.spawnParticle(Particle.EXPLOSION_NORMAL, location, 3);
    world.playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 1 f, 1 f);

    for (Entity nearby: world.getNearbyEntities(location, 4 d, 4 d, 4 d)) {
        if ( /*entity has some condition that DOES NOT protect it*/ ) {
            if (nearby instanceof LivingEntity) {
                LivingEntity entity = (LivingEntity) nearby;
                //Damage 5 hearts or whatever amount you want
                entity.damage(5 d);
            }
        }
    }

    Second method:
    Code (Java):
    World world = Bukkit.getServer().getWorlds().get(0);
    Location location = /*the explosion location*/ ;

    TNTPrimed tnt = world.spawn(location, TNTPrimed.class);
    //Instant explosion
    tnt.setFuseTicks(1);
    tnt.setCustomName("CustomTNT");
    tnt.setCustomNameVisible(false);
     
    Code (Java):
    //This will avoid errors if you clear the set and add entities at the same time
    Set < UUID > noDamageEntity = Collections.newSetFromMap(new ConcurrentHashMap < > ());

    @EventHandler
    public final void explode(EntityExplodeEvent e) {
        Entity entity = e.getEntity();

        if (entity instanceof TNTPrimed) {
            TNTPrimed tnt = (TNTPrimed) entity;
            String name = tnt.getCustomName();
            if (name != null) {
                if (name.equals("CustomTNT")) {
                    List < Block > ignore = new ArrayList < > ();
                    for (Block block: e.blockList()) {
                        //Check if the block has some condition that would protect him
                        if (block.getType().equals(Material.DIRT)) {
                            ignore.add(block);
                        }

                        noDamageEntity.addAll(block.getWorld().getNearbyEntities(block.getLocation(), 1d, 1d, 1d));
                    }

                    //To just ignore all blocks, do e.blockList().clear();
                    e.blockList().removeAll(ignore);
                }
            }
        }
    }

    @EventHandler
    public final void damage(EntityDamageEvent e) {
        Entity entity = e.getEntity();
        if (noDamageEntity.contains(entity.getUniqueId())) {
            e.setCancelled(true);
            noDamageEntity.remove(entity.getUniqueId());
        }
    }
    See also TNTPrimed javadocs for more information

    ( Doing the first method will also call the EntityExplodeEvent )
     
    #2 KarmaConfigs, Jun 28, 2021
    Last edited: Jun 28, 2021
  3. for the first method, what can I do to detect if the entity is a player?
    Edit: I figured it out
     
    #3 mason-walker, Jun 28, 2021
    Last edited: Jun 28, 2021
Thread Status:
Not open for further replies.