From c5802faefcd38184f5c5bc3f261bb8cdfe2b8b3e Mon Sep 17 00:00:00 2001 From: Andreas Troelsen Date: Tue, 23 Jul 2024 01:00:43 +0200 Subject: [PATCH] Refactor `obsidian-bomb` explosions. This commit changes the "source" of the explosions from `obsidian-bomb` to _something_ that isn't the boss itself. Originally, these explosions were block explosions, but without a "source" from the damage caused to other mobs, the `monster-infight` flag was largely ignored. By switching to "entity explosions" with the boss as the "source", the flag was now respected, and mobs would no longer take damage from these explosions if the `monster-infight` flag was set to `false`. However, the handler for "entity explosions" now started reacting to the explosions caused by the `obsidian-bomb` ability as if they were normal entity explosions, e.g. those caused by creepers, and because entities that explode usually "die" (although without an EntityDeathEvent), the handler removes the entity from the monster manager, which effectively "unregisters" the boss, leaving the entity itself just hanging around in the arena as a normal mob (with a huge health pool). The "obvious" solution is to change back to "block explosions", and that could perhaps have worked if the API had consistent interplay between an "explode event" and the resulting "damage event". It turns out that the EntityExplodeEvent results in an EntityDamageByEntityEvent, and the same can be said for BlockExplodeEvent and EntityDamageByBlockEvent, except the latter will have a `null` block in it, so even if we were to attach some metadata to the block, we wouldn't be able to retrieve it in the damage handler. So we're sticking with "entity explosions"... The hacky solution: We just spawn a new entity and pin the explosion on it instead of the boss. That way the new entity is removed by the entity explosion handler (which is a no-op, because the entity isn't an arena monster) instead of the boss. It technically doesn't matter which entity we spawn, but by spawning a primed TNT block, we can naturally stick a source on it, and the damage handler will treat it as if the boss placed a TNT block and detonated it, which is an apt analogy after all. Just to make sure we don't forget the dual responsibility, we've added a little comment in the damage handler. An alternative solution would have been to spawn any other entity and stick the boss entity ID on it, then look up the entity by that ID in the damage handler if the damager had metadata on it. This is just a bit more streamlined and likely a lot more performant. Fixes #789 --- changelog.md | 1 + .../java/com/garbagemule/MobArena/ArenaListener.java | 1 + .../MobArena/waves/ability/core/ObsidianBomb.java | 11 +++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index ee5cded..5fb10d5 100644 --- a/changelog.md +++ b/changelog.md @@ -18,6 +18,7 @@ These changes will (most likely) be included in the next version. ### Fixed - MobArena no longer throws errors when handling block explosions on Minecraft 1.21. - The `shuffle-positions` ability now correctly shuffles the position of the boss as well if `monster-teleport` is set to `false`. +- The `obsidian-bomb` ability no longer breaks boss waves. ## [0.108] - 2024-01-01 ### Added diff --git a/src/main/java/com/garbagemule/MobArena/ArenaListener.java b/src/main/java/com/garbagemule/MobArena/ArenaListener.java index a8503cd..a0c4083 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaListener.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaListener.java @@ -687,6 +687,7 @@ public class ArenaListener } } + // This also covers the Obsidian Bomb ability! if (damager instanceof TNTPrimed) { damager = ((TNTPrimed) damager).getSource(); } diff --git a/src/main/java/com/garbagemule/MobArena/waves/ability/core/ObsidianBomb.java b/src/main/java/com/garbagemule/MobArena/waves/ability/core/ObsidianBomb.java index e22db01..80cf686 100644 --- a/src/main/java/com/garbagemule/MobArena/waves/ability/core/ObsidianBomb.java +++ b/src/main/java/com/garbagemule/MobArena/waves/ability/core/ObsidianBomb.java @@ -12,6 +12,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.TNTPrimed; @AbilityInfo( name = "Obsidian Bomb", @@ -54,8 +55,14 @@ public class ObsidianBomb implements Ability if (!arena.isRunning()) return; - world.getBlockAt(loc).setType(Material.AIR); - world.createExplosion(loc, 3F, false, true, boss.getEntity()); + TNTPrimed scapegoat = world.spawn(loc, TNTPrimed.class); + scapegoat.setSource(boss.getEntity()); + try { + world.getBlockAt(loc).setType(Material.AIR); + world.createExplosion(loc, 3F, false, true, scapegoat); + } finally { + scapegoat.remove(); + } } }, FUSE); }