From 47c10005c1cb4d456fedc26eaf6d8c4747204527 Mon Sep 17 00:00:00 2001
From: Iceee <andrew@opticgaming.tv>
Date: Wed, 2 Mar 2016 23:00:53 -0600
Subject: [PATCH] Configurable TNT cannon fix


diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 7028730..abed8ea 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -231,4 +231,10 @@ public class PaperWorldConfig {
     private void mobSpawnerTickRate() {
         mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
     }
+
+    public boolean fixCannons;
+    private void fixCannons() {
+        fixCannons = getBoolean("fix-cannons", false);
+        log("Fix TNT cannons: " + fixCannons);
+    }
 }
diff --git a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java
index ffc07cd..64aaba4 100644
--- a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java
+++ b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java
@@ -76,6 +76,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal {
         } else {
             this.b(world, blockposition, iblockdata, 0);
             world.setAir(blockposition);
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                world.applyPhysics(blockposition.shift(EnumDirection.EAST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.WEST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.UP), this);
+                return;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i = aenumdirection.length;
 
@@ -173,6 +184,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal {
 
     public void postBreak(World world, BlockPosition blockposition, IBlockData iblockdata) {
         if (this.d) {
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                world.applyPhysics(blockposition.shift(EnumDirection.EAST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.WEST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.UP), this);
+                return;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i = aenumdirection.length;
 
diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java
index cce1cd7..7f5a112 100644
--- a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java
+++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java
@@ -52,6 +52,17 @@ public class BlockRedstoneTorch extends BlockTorch {
 
     public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
         if (this.isOn) {
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.UP), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.WEST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.EAST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this);
+                return;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i = aenumdirection.length;
 
@@ -66,6 +77,17 @@ public class BlockRedstoneTorch extends BlockTorch {
 
     public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) {
         if (this.isOn) {
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.UP), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.WEST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.EAST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this);
+                return;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i = aenumdirection.length;
 
diff --git a/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/src/main/java/net/minecraft/server/BlockRedstoneWire.java
index 1a133d9..f4f9be6 100644
--- a/src/main/java/net/minecraft/server/BlockRedstoneWire.java
+++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java
@@ -184,6 +184,17 @@ public class BlockRedstoneWire extends Block {
             }
 
             this.B.add(blockposition);
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                this.B.add(blockposition.shift(EnumDirection.WEST));
+                this.B.add(blockposition.shift(EnumDirection.EAST));
+                this.B.add(blockposition.shift(EnumDirection.DOWN));
+                this.B.add(blockposition.shift(EnumDirection.UP));
+                this.B.add(blockposition.shift(EnumDirection.NORTH));
+                this.B.add(blockposition.shift(EnumDirection.SOUTH));
+                return iblockdata;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i1 = aenumdirection.length;
 
@@ -200,6 +211,17 @@ public class BlockRedstoneWire extends Block {
     private void b(World world, BlockPosition blockposition) {
         if (world.getType(blockposition).getBlock() == this) {
             world.applyPhysics(blockposition, this);
+            // Paper start - Fix cannons
+            if (world.paperConfig.fixCannons) {
+                world.applyPhysics(blockposition.shift(EnumDirection.WEST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.EAST), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this);
+                world.applyPhysics(blockposition.shift(EnumDirection.UP), this);
+                return;
+            }
+            // Paper end
             EnumDirection[] aenumdirection = EnumDirection.values();
             int i = aenumdirection.length;
 
diff --git a/src/main/java/net/minecraft/server/BlockTNT.java b/src/main/java/net/minecraft/server/BlockTNT.java
index 3b799bf..e6c0ffb 100644
--- a/src/main/java/net/minecraft/server/BlockTNT.java
+++ b/src/main/java/net/minecraft/server/BlockTNT.java
@@ -29,7 +29,11 @@ public class BlockTNT extends Block {
 
     public void wasExploded(World world, BlockPosition blockposition, Explosion explosion) {
         if (!world.isClientSide) {
-            EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource());
+            // Paper start - Fix cannons
+            double y = blockposition.getY();
+            if (!world.paperConfig.fixCannons) y += 0.5;
+            EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource());
+            // Paper end
 
             entitytntprimed.setFuseTicks((short) (world.random.nextInt(entitytntprimed.getFuseTicks() / 4) + entitytntprimed.getFuseTicks() / 8));
             world.addEntity(entitytntprimed);
@@ -43,7 +47,11 @@ public class BlockTNT extends Block {
     public void a(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving) {
         if (!world.isClientSide) {
             if (((Boolean) iblockdata.get(BlockTNT.EXPLODE)).booleanValue()) {
-                EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), entityliving);
+                // Paper start - Fix cannons
+                double y = blockposition.getY();
+                if (!world.paperConfig.fixCannons) y += 0.5;
+                EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), entityliving);
+                // Paper end
 
                 world.addEntity(entitytntprimed);
                 world.a((EntityHuman) null, entitytntprimed.locX, entitytntprimed.locY, entitytntprimed.locZ, SoundEffects.gk, SoundCategory.BLOCKS, 1.0F, 1.0F);
diff --git a/src/main/java/net/minecraft/server/DispenserRegistry.java b/src/main/java/net/minecraft/server/DispenserRegistry.java
index 392e2fa..a93a990 100644
--- a/src/main/java/net/minecraft/server/DispenserRegistry.java
+++ b/src/main/java/net/minecraft/server/DispenserRegistry.java
@@ -497,7 +497,11 @@ public class DispenserRegistry {
                 org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ());
                 CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
 
-                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D));
+                // Paper start - Fix cannons
+                double y = blockposition.getY();
+                if (!world.paperConfig.fixCannons) y += 0.5;
+                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, y, (double) blockposition.getZ() + 0.5D));
+                // Paper end
                 if (!BlockDispenser.eventFired) {
                    world.getServer().getPluginManager().callEvent(event);
                 }
diff --git a/src/main/java/net/minecraft/server/EntityFallingBlock.java b/src/main/java/net/minecraft/server/EntityFallingBlock.java
index 8f2b253..23fb154 100644
--- a/src/main/java/net/minecraft/server/EntityFallingBlock.java
+++ b/src/main/java/net/minecraft/server/EntityFallingBlock.java
@@ -274,4 +274,22 @@ public class EntityFallingBlock extends Entity {
     public boolean br() {
         return true;
     }
+
+    // Paper start - Fix cannons
+    @Override
+    public double f(double d0, double d1, double d2) {
+        if (!world.paperConfig.fixCannons) return super.f(d0, d1, d2);
+
+        double d3 = this.locX - d0;
+        double d4 = this.locY + this.getHeadHeight() - d1;
+        double d5 = this.locZ - d2;
+
+        return (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
+    }
+
+    @Override
+    public float getHeadHeight() {
+        return world.paperConfig.fixCannons ? this.length / 2 : super.getHeadHeight();
+    }
+    // Paper end
 }
diff --git a/src/main/java/net/minecraft/server/EntityTNTPrimed.java b/src/main/java/net/minecraft/server/EntityTNTPrimed.java
index 1113b1c..12feacf 100644
--- a/src/main/java/net/minecraft/server/EntityTNTPrimed.java
+++ b/src/main/java/net/minecraft/server/EntityTNTPrimed.java
@@ -30,6 +30,7 @@ public class EntityTNTPrimed extends Entity {
         this.lastY = d1;
         this.lastZ = d2;
         this.source = entityliving;
+        if (world.paperConfig.fixCannons) this.motX = this.motZ = 0.0F; // Paper - Fix cannons
     }
 
     protected void i() {
@@ -118,9 +119,66 @@ public class EntityTNTPrimed extends Entity {
         return this.source;
     }
 
+    // Paper start - Fix cannons
+    @Override
+    public double f(double d0, double d1, double d2) {
+        if (!world.paperConfig.fixCannons) return super.f(d0, d1, d2);
+
+        double d3 = this.locX - d0;
+        double d4 = this.locY + this.getHeadHeight() - d1;
+        double d5 = this.locZ - d2;
+
+        return (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
+    }
+
+    @Override
+    public boolean bd() {
+        return !world.paperConfig.fixCannons && super.bd();
+    }
+
+    @Override
     public float getHeadHeight() {
-        return 0.0F;
+        return world.paperConfig.fixCannons ? this.length / 2 : 0.0F;
+    }
+
+    /**
+     * Author: Jedediah Smith <jedediah@silencegreys.com>
+     */
+    @Override
+    public boolean aj() {
+        if (!world.paperConfig.fixCannons) return super.aj();
+
+        // Preserve velocity while calling the super method
+        double oldMotX = this.motX;
+        double oldMotY = this.motY;
+        double oldMotZ = this.motZ;
+
+        super.aj();
+
+        this.motX = oldMotX;
+        this.motY = oldMotY;
+        this.motZ = oldMotZ;
+
+        if (this.inWater) {
+            // Send position and velocity updates to nearby players on every tick while the TNT is in water.
+            // This does pretty well at keeping their clients in sync with the server.
+            EntityTrackerEntry ete = ((WorldServer) this.getWorld()).getTracker().trackedEntities.get(this.getId());
+            if (ete != null) {
+                PacketPlayOutEntityVelocity velocityPacket = new PacketPlayOutEntityVelocity(this);
+                PacketPlayOutEntityTeleport positionPacket = new PacketPlayOutEntityTeleport(this);
+
+                for (EntityPlayer viewer : ete.trackedPlayers) {
+                    if ((viewer.locX - this.locX) * (viewer.locY - this.locY) * (viewer.locZ - this.locZ) < 16 * 16) {
+                        viewer.playerConnection.sendPacket(velocityPacket);
+                        viewer.playerConnection.sendPacket(positionPacket);
+                    }
+                }
+            }
+        }
+
+        return this.inWater;
     }
+    // Paper end
 
     public void setFuseTicks(int i) {
         this.datawatcher.set(EntityTNTPrimed.FUSE_TICKS, Integer.valueOf(i));
diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java
index 91540c7..209b470 100644
--- a/src/main/java/net/minecraft/server/Explosion.java
+++ b/src/main/java/net/minecraft/server/Explosion.java
@@ -148,9 +148,16 @@ public class Explosion {
                             d14 = entity instanceof EntityHuman && world.paperConfig.disableExplosionKnockback ? 0 : EnchantmentProtection.a((EntityLiving) entity, d13); // Paper - Disable explosion knockback
                         }
 
+                        // Paper start - Fix cannons
+                        /*
                         entity.motX += d8 * d14;
                         entity.motY += d9 * d14;
                         entity.motZ += d10 * d14;
+                        */
+                        // This impulse method sets the dirty flag, so clients will get an immediate velocity update
+                        entity.g(d8 * d14, d9 * d14, d10 * d14);
+                        // Paper end
+
                         if (entity instanceof EntityHuman) {
                             EntityHuman entityhuman = (EntityHuman) entity;
 
-- 
2.7.4