--- a/net/minecraft/world/entity/vehicle/MinecartTNT.java
+++ b/net/minecraft/world/entity/vehicle/MinecartTNT.java
@@ -9,18 +9,26 @@
 import net.minecraft.tags.BlockTags;
 import net.minecraft.tags.DamageTypeTags;
 import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.entity.projectile.AbstractArrow;
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.level.BlockGetter;
 import net.minecraft.world.level.Explosion;
+import net.minecraft.world.level.ExplosionDamageCalculator;
 import net.minecraft.world.level.Level;
 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.EntityRemoveEvent;
+import org.bukkit.event.entity.ExplosionPrimeEvent;
+// CraftBukkit end
 
 public class MinecartTNT extends AbstractMinecart {
+
     private static final byte EVENT_PRIME = 10;
     public int fuse = -1;
 
@@ -46,25 +54,38 @@
     public void tick() {
         super.tick();
         if (this.fuse > 0) {
-            this.fuse--;
-            this.level().addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5, this.getZ(), 0.0, 0.0, 0.0);
+            // Paper start - Configurable TNT height nerf
+            if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
+                this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD);
+                return;
+            }
+            // Paper end - Configurable TNT height nerf
+            --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) {
             this.explode(this.getDeltaMovement().horizontalDistanceSqr());
         }
 
         if (this.horizontalCollision) {
-            double d = this.getDeltaMovement().horizontalDistanceSqr();
-            if (d >= 0.01F) {
-                this.explode(d);
+            double d0 = this.getDeltaMovement().horizontalDistanceSqr();
+
+            if (d0 >= 0.009999999776482582D) {
+                this.explode(d0);
             }
         }
+
     }
 
     @Override
     public boolean hurt(DamageSource source, float amount) {
-        if (source.getDirectEntity() instanceof AbstractArrow abstractArrow && abstractArrow.isOnFire()) {
-            DamageSource damageSource = this.damageSources().explosion(this, source.getEntity());
-            this.explode(damageSource, abstractArrow.getDeltaMovement().lengthSqr());
+        Entity entity = source.getDirectEntity();
+
+        if (entity instanceof AbstractArrow entityarrow) {
+            if (entityarrow.isOnFire()) {
+                DamageSource damagesource1 = this.damageSources().explosion(this, source.getEntity());
+
+                this.explode(damagesource1, entityarrow.getDeltaMovement().lengthSqr());
+            }
         }
 
         return super.hurt(source, amount);
@@ -72,14 +93,16 @@
 
     @Override
     public void destroy(DamageSource source) {
-        double d = this.getDeltaMovement().horizontalDistanceSqr();
-        if (!damageSourceIgnitesTnt(source) && !(d >= 0.01F)) {
+        double d0 = this.getDeltaMovement().horizontalDistanceSqr();
+
+        if (!MinecartTNT.damageSourceIgnitesTnt(source) && d0 < 0.009999999776482582D) {
             this.destroy(this.getDropItem());
         } else {
             if (this.fuse < 0) {
                 this.primeFuse();
                 this.fuse = this.random.nextInt(20) + this.random.nextInt(20);
             }
+
         }
     }
 
@@ -89,37 +112,37 @@
     }
 
     public void explode(double power) {
-        this.explode(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.0) {
-                d = 5.0;
+            double d1 = Math.sqrt(power);
+
+            if (d1 > 5.0D) {
+                d1 = 5.0D;
             }
 
-            this.level()
-                .explode(
-                    this,
-                    damageSource,
-                    null,
-                    this.getX(),
-                    this.getY(),
-                    this.getZ(),
-                    (float)(4.0 + this.random.nextDouble() * 1.5 * d),
-                    false,
-                    Level.ExplosionInteraction.TNT
-                );
-            this.discard();
+            // 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(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
         }
+
     }
 
     @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);
@@ -130,6 +153,7 @@
         if (powered && this.fuse < 0) {
             this.primeFuse();
         }
+
     }
 
     @Override
@@ -139,16 +163,18 @@
         } else {
             super.handleEntityEvent(status);
         }
+
     }
 
     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(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);
             }
         }
+
     }
 
     public int getFuse() {
@@ -161,15 +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);
+        return this.isPrimed() && (state.is(BlockTags.RAILS) || world.getBlockState(pos.above()).is(BlockTags.RAILS)) ? false : super.shouldBlockExplode(explosion, world, pos, state, explosionPower);
     }
 
     @Override
@@ -178,6 +201,7 @@
         if (nbt.contains("TNTFuse", 99)) {
             this.fuse = nbt.getInt("TNTFuse");
         }
+
     }
 
     @Override
@@ -188,7 +212,7 @@
 
     @Override
     boolean shouldSourceDestroy(DamageSource source) {
-        return damageSourceIgnitesTnt(source);
+        return MinecartTNT.damageSourceIgnitesTnt(source);
     }
 
     private static boolean damageSourceIgnitesTnt(DamageSource source) {
