--- a/net/minecraft/world/entity/vehicle/MinecartTNT.java
+++ b/net/minecraft/world/entity/vehicle/MinecartTNT.java
@@ -21,8 +21,12 @@
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.level.material.FluidState;
+// CraftBukkit start
+import org.bukkit.event.entity.ExplosionPrimeEvent;
+// CraftBukkit end
 
 public class MinecartTNT extends AbstractMinecart {
+
     private static final byte EVENT_PRIME = 10;
     public int fuse = -1;
 
@@ -48,6 +52,12 @@
     public void tick() {
         super.tick();
         if (this.fuse > 0) {
+            // Paper start - Configurable TNT entity height nerf
+            if (this.level.paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
+                this.discard();
+                return;
+            }
+            // Paper end
             --this.fuse;
             this.level.addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5D, this.getZ(), 0.0D, 0.0D, 0.0D);
         } else if (this.fuse == 0) {
@@ -55,9 +65,10 @@
         }
 
         if (this.horizontalCollision) {
-            double d = this.getDeltaMovement().horizontalDistanceSqr();
-            if (d >= (double)0.01F) {
-                this.explode(d);
+            double d0 = this.getDeltaMovement().horizontalDistanceSqr();
+
+            if (d0 >= 0.009999999776482582D) {
+                this.explode(d0);
             }
         }
 
@@ -66,10 +77,14 @@
     @Override
     public boolean hurt(DamageSource source, float amount) {
         Entity entity = source.getDirectEntity();
-        if (entity instanceof AbstractArrow abstractArrow) {
-            if (abstractArrow.isOnFire()) {
-                DamageSource damageSource = DamageSource.explosion(this, source.getEntity());
-                this.explode(damageSource, abstractArrow.getDeltaMovement().lengthSqr());
+
+        if (entity instanceof AbstractArrow) {
+            AbstractArrow entityarrow = (AbstractArrow) entity;
+
+            if (entityarrow.isOnFire()) {
+                DamageSource damagesource1 = DamageSource.explosion(this, source.getEntity());
+
+                this.explode(damagesource1, entityarrow.getDeltaMovement().lengthSqr());
             }
         }
 
@@ -78,8 +93,9 @@
 
     @Override
     public void destroy(DamageSource damageSource) {
-        double d = this.getDeltaMovement().horizontalDistanceSqr();
-        if (!damageSource.isFire() && !damageSource.isExplosion() && !(d >= (double)0.01F)) {
+        double d0 = this.getDeltaMovement().horizontalDistanceSqr();
+
+        if (!damageSource.isFire() && !damageSource.isExplosion() && d0 < 0.009999999776482582D) {
             super.destroy(damageSource);
         } else {
             if (this.fuse < 0) {
@@ -96,17 +112,26 @@
     }
 
     protected void explode(double power) {
-        this.explode((DamageSource)null, power);
+        this.explode((DamageSource) null, power);
     }
 
     protected void explode(@Nullable DamageSource damageSource, double power) {
         if (!this.level.isClientSide) {
-            double d = Math.sqrt(power);
-            if (d > 5.0D) {
-                d = 5.0D;
+            double d1 = Math.sqrt(power);
+
+            if (d1 > 5.0D) {
+                d1 = 5.0D;
             }
 
-            this.level.explode(this, damageSource, (ExplosionDamageCalculator)null, this.getX(), this.getY(), this.getZ(), (float)(4.0D + this.random.nextDouble() * 1.5D * d), false, Level.ExplosionInteraction.TNT);
+            // CraftBukkit start
+            ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), (float) (4.0D + this.random.nextDouble() * 1.5D * d1), false);
+            this.level.getCraftServer().getPluginManager().callEvent(event);
+            if (event.isCancelled()) {
+                this.fuse = -1;
+                return;
+            }
+            this.level.explode(this, damageSource, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT);
+            // CraftBukkit end
             this.discard();
         }
 
@@ -115,8 +140,9 @@
     @Override
     public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
         if (fallDistance >= 3.0F) {
-            float f = fallDistance / 10.0F;
-            this.explode((double)(f * f));
+            float f2 = fallDistance / 10.0F;
+
+            this.explode((double) (f2 * f2));
         }
 
         return super.causeFallDamage(fallDistance, damageMultiplier, damageSource);
@@ -143,9 +169,9 @@
     public void primeFuse() {
         this.fuse = 80;
         if (!this.level.isClientSide) {
-            this.level.broadcastEntityEvent(this, (byte)10);
+            this.level.broadcastEntityEvent(this, (byte) 10);
             if (!this.isSilent()) {
-                this.level.playSound((Player)null, this.getX(), this.getY(), this.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
+                this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
             }
         }
 
@@ -161,12 +187,12 @@
 
     @Override
     public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
-        return !this.isPrimed() || !blockState.is(BlockTags.RAILS) && !world.getBlockState(pos.above()).is(BlockTags.RAILS) ? super.getBlockExplosionResistance(explosion, world, pos, blockState, fluidState, max) : 0.0F;
+        return this.isPrimed() && (blockState.is(BlockTags.RAILS) || world.getBlockState(pos.above()).is(BlockTags.RAILS)) ? 0.0F : super.getBlockExplosionResistance(explosion, world, pos, blockState, fluidState, max);
     }
 
     @Override
     public boolean shouldBlockExplode(Explosion explosion, BlockGetter world, BlockPos pos, BlockState state, float explosionPower) {
-        return !this.isPrimed() || !state.is(BlockTags.RAILS) && !world.getBlockState(pos.above()).is(BlockTags.RAILS) ? super.shouldBlockExplode(explosion, world, pos, state, explosionPower) : false;
+        return this.isPrimed() && (state.is(BlockTags.RAILS) || world.getBlockState(pos.above()).is(BlockTags.RAILS)) ? false : super.shouldBlockExplode(explosion, world, pos, state, explosionPower);
     }
 
     @Override
