From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 31 Oct 2020 18:43:02 -0500
Subject: [PATCH] Strip raytracing for EntityLiving#hasLineOfSight

The IBlockAccess#rayTrace method is very wasteful in both allocations,
and in logic. While EntityLiving#hasLineOfSight provides static
parameters for collisions with blocks and fluids, the method still does
a lot of dynamic checks for both of these, which result in extra work.
As well, since the fluid collision option is set to NONE, the entire
fluid collision system is completely unneeded, yet used anyways.

Airplane
Copyright (C) 2020 Technove LLC

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

diff --git a/src/main/java/net/minecraft/util/MathHelper.java b/src/main/java/net/minecraft/util/MathHelper.java
index cc566784c7dd21cc2c44e0f351347f657e57ddcf..e9e7fcf2b63febe2a7d055826fabb86bc13a5cf3 100644
--- a/src/main/java/net/minecraft/util/MathHelper.java
+++ b/src/main/java/net/minecraft/util/MathHelper.java
@@ -240,6 +240,7 @@ public class MathHelper {
         return f - (float) d(f);
     }
 
+    public static double getDecimals(double num) { return h(num); } // Airplane
     public static double h(double d0) {
         return d0 - (double) d(d0);
     }
@@ -418,6 +419,7 @@ public class MathHelper {
         return f1 + f * (f2 - f1);
     }
 
+    public static double linearInterpolation(double value1, double value2, double amount) { return d(value1, value2, amount); } // Airplane - OBFHELPER
     public static double d(double d0, double d1, double d2) {
         return d1 + d0 * (d2 - d1);
     }
@@ -434,6 +436,7 @@ public class MathHelper {
         return d0 * d0 * d0 * (d0 * (d0 * 6.0D - 15.0D) + 10.0D);
     }
 
+    public static int sign(double num) { return k(num); } // Airplane - OBFHELPER
     public static int k(double d0) {
         return d0 == 0.0D ? 0 : (d0 > 0.0D ? 1 : -1);
     }
diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java
index 96cc46a26eef701b0579f3407e67af9176e1743b..5c7ce20609a1c18687696581a76f21a1b182ea7c 100644
--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java
+++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java
@@ -111,6 +111,7 @@ import net.minecraft.world.phys.AxisAlignedBB;
 import net.minecraft.world.phys.MovingObjectPosition;
 import net.minecraft.world.phys.MovingObjectPositionEntity;
 import net.minecraft.world.phys.Vec3D;
+import net.minecraft.world.phys.shapes.VoxelShapeCollision;
 import net.minecraft.world.scores.ScoreboardTeam;
 import org.apache.logging.log4j.Logger;
 
@@ -3101,7 +3102,7 @@ public abstract class EntityLiving extends Entity {
         Vec3D vec3d = new Vec3D(this.locX(), this.getHeadY(), this.locZ());
         Vec3D vec3d1 = new Vec3D(entity.locX(), entity.getHeadY(), entity.locZ());
 
-        return this.world.rayTrace(new RayTrace(vec3d, vec3d1, RayTrace.BlockCollisionOption.COLLIDER, RayTrace.FluidCollisionOption.NONE, this)).getType() == MovingObjectPosition.EnumMovingObjectType.MISS;
+        return this.world.rayTraceDirect(vec3d, vec3d1, VoxelShapeCollision.a(this)) == MovingObjectPosition.EnumMovingObjectType.MISS; // Airplane - use direct method
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/world/level/IBlockAccess.java b/src/main/java/net/minecraft/world/level/IBlockAccess.java
index e612e1d30f76e217b1aa23488ab025adce048f57..c9198d242b9053fad6fa5b53c1894679002d50a7 100644
--- a/src/main/java/net/minecraft/world/level/IBlockAccess.java
+++ b/src/main/java/net/minecraft/world/level/IBlockAccess.java
@@ -14,9 +14,11 @@ import net.minecraft.world.level.block.state.IBlockData;
 import net.minecraft.world.level.material.Fluid;
 import net.minecraft.world.level.material.Material;
 import net.minecraft.world.phys.AxisAlignedBB;
+import net.minecraft.world.phys.MovingObjectPosition;
 import net.minecraft.world.phys.MovingObjectPositionBlock;
 import net.minecraft.world.phys.Vec3D;
 import net.minecraft.world.phys.shapes.VoxelShape;
+import net.minecraft.world.phys.shapes.VoxelShapeCollision;
 
 public interface IBlockAccess {
 
@@ -56,6 +58,15 @@ public interface IBlockAccess {
         return BlockPosition.a(axisalignedbb).map(this::getType);
     }
 
+    // Airplane start - broken down variant of below rayTraceBlock, used by World#rayTraceDirect
+    default MovingObjectPosition.EnumMovingObjectType rayTraceBlockDirect(Vec3D vec3d, Vec3D vec3d1, BlockPosition blockposition, IBlockData iblockdata, VoxelShapeCollision voxelshapecoll) {
+        VoxelShape voxelshape = RayTrace.BlockCollisionOption.COLLIDER.get(iblockdata, this, blockposition, voxelshapecoll);
+        MovingObjectPositionBlock movingobjectpositionblock = this.rayTrace(vec3d, vec3d1, blockposition, voxelshape, iblockdata);
+
+        return movingobjectpositionblock == null ? null : movingobjectpositionblock.getType();
+    }
+    // Airplane end
+
     // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
     default MovingObjectPositionBlock rayTraceBlock(RayTrace raytrace1, BlockPosition blockposition) {
             // Paper start - Prevent raytrace from loading chunks
diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java
index af01f5d635eada7175b9d7fdb47a65530686a539..3e08e56f67516333e7d880fdc595447a3ae4dc83 100644
--- a/src/main/java/net/minecraft/world/level/World.java
+++ b/src/main/java/net/minecraft/world/level/World.java
@@ -69,6 +69,8 @@ import net.minecraft.world.level.saveddata.maps.WorldMap;
 import net.minecraft.world.level.storage.WorldData;
 import net.minecraft.world.level.storage.WorldDataMutable;
 import net.minecraft.world.phys.AxisAlignedBB;
+import net.minecraft.world.phys.MovingObjectPosition;
+import net.minecraft.world.phys.Vec3D;
 import net.minecraft.world.phys.shapes.OperatorBoolean;
 import net.minecraft.world.phys.shapes.VoxelShape;
 import net.minecraft.world.phys.shapes.VoxelShapeCollision;
@@ -378,6 +380,91 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
         return null;
     }
 
+    // Airplane start - broken down method of raytracing for EntityLiving#hasLineOfSight, replaces IBlockAccess#rayTrace(RayTrace)
+    public MovingObjectPosition.EnumMovingObjectType rayTraceDirect(Vec3D vec3d, Vec3D vec3d1, VoxelShapeCollision voxelshapecoll) {
+        // most of this code comes from IBlockAccess#a(RayTrace, BiFunction, Function), but removes the needless functions
+        if (vec3d.equals(vec3d1)) {
+            return MovingObjectPosition.EnumMovingObjectType.MISS;
+        }
+
+        double endX = MathHelper.linearInterpolation(-1.0E-7D, vec3d1.x, vec3d.x);
+        double endY = MathHelper.linearInterpolation(-1.0E-7D, vec3d1.y, vec3d.y);
+        double endZ = MathHelper.linearInterpolation(-1.0E-7D, vec3d1.z, vec3d.z);
+
+        double startX = MathHelper.linearInterpolation(-1.0E-7D, vec3d.x, vec3d1.x);
+        double startY = MathHelper.linearInterpolation(-1.0E-7D, vec3d.y, vec3d1.y);
+        double startZ = MathHelper.linearInterpolation(-1.0E-7D, vec3d.z, vec3d1.z);
+
+        int currentX = MathHelper.floor(startX);
+        int currentY = MathHelper.floor(startY);
+        int currentZ = MathHelper.floor(startZ);
+
+        BlockPosition.MutableBlockPosition currentBlock = new BlockPosition.MutableBlockPosition(currentX, currentY, currentZ);
+
+        Chunk chunk = this.getChunkIfLoaded(currentBlock);
+        if (chunk == null) {
+            return MovingObjectPosition.EnumMovingObjectType.MISS;
+        }
+
+        MovingObjectPosition.EnumMovingObjectType initialCheck = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getType(currentBlock), voxelshapecoll);
+
+        if (initialCheck != null) {
+            return initialCheck;
+        }
+
+        double diffX = endX - startX;
+        double diffY = endY - startY;
+        double diffZ = endZ - startZ;
+
+        int xDirection = MathHelper.sign(diffX);
+        int yDirection = MathHelper.sign(diffY);
+        int zDirection = MathHelper.sign(diffZ);
+
+        double normalizedX = xDirection == 0 ? Double.MAX_VALUE : (double) xDirection / diffX;
+        double normalizedY = yDirection == 0 ? Double.MAX_VALUE : (double) yDirection / diffY;
+        double normalizedZ = zDirection == 0 ? Double.MAX_VALUE : (double) zDirection / diffZ;
+
+        double normalizedXDirection = normalizedX * (xDirection > 0 ? 1.0D - MathHelper.getDecimals(startX) : MathHelper.getDecimals(startX));
+        double normalizedYDirection = normalizedY * (yDirection > 0 ? 1.0D - MathHelper.getDecimals(startY) : MathHelper.getDecimals(startY));
+        double normalizedZDirection = normalizedZ * (zDirection > 0 ? 1.0D - MathHelper.getDecimals(startZ) : MathHelper.getDecimals(startZ));
+
+        MovingObjectPosition.EnumMovingObjectType result;
+
+        do {
+            if (normalizedXDirection > 1.0D && normalizedYDirection > 1.0D && normalizedZDirection > 1.0D) {
+                return MovingObjectPosition.EnumMovingObjectType.MISS;
+            }
+
+            if (normalizedXDirection < normalizedYDirection) {
+                if (normalizedXDirection < normalizedZDirection) {
+                    currentX += xDirection;
+                    normalizedXDirection += normalizedX;
+                } else {
+                    currentZ += zDirection;
+                    normalizedZDirection += normalizedZ;
+                }
+            } else if (normalizedYDirection < normalizedZDirection) {
+                currentY += yDirection;
+                normalizedYDirection += normalizedY;
+            } else {
+                currentZ += zDirection;
+                normalizedZDirection += normalizedZ;
+            }
+
+            currentBlock.setValues(currentX, currentY, currentZ);
+            if (chunk.getPos().x != currentBlock.getX() >> 4 || chunk.getPos().z != currentBlock.getZ() >> 4) {
+                chunk = this.getChunkIfLoaded(currentBlock);
+                if (chunk == null) {
+                    return MovingObjectPosition.EnumMovingObjectType.MISS;
+                }
+            }
+            result = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getType(currentBlock), voxelshapecoll);
+        } while (result == null);
+
+        return result;
+    }
+    // Airplane end
+
     public static boolean isValidLocation(BlockPosition blockposition) {
         return blockposition.isValidLocation(); // Paper - use better/optimized check
     }
