From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Sun, 14 Aug 2022 10:28:52 +0800 Subject: [PATCH] Strip raytracing for EntityLiving#hasLineOfSight This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 5189762e0f9cae84b7bc60a22437cef4e95c7c36..029f456504f0229a564af937e30329ca08a1b5f9 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -3618,7 +3618,13 @@ public abstract class LivingEntity extends Entity implements Attackable { Vec3 vec3d1 = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ()); // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists - return vec3d1.distanceToSqr(vec3d) > 128D * 128D ? false : this.level.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS; // Paper - use distanceToSqr + // Leaves start - strip raytracing + if (top.leavesmc.leaves.LeavesConfig.entityStripRaytracing) { + return vec3d1.distanceToSqr(vec3d) > 128D * 128D ? false : this.level.rayTraceDirect(vec3d, vec3d1, net.minecraft.world.phys.shapes.CollisionContext.of(this)) == net.minecraft.world.phys.BlockHitResult.Type.MISS; + } else { + return vec3d1.distanceToSqr(vec3d) > 128D * 128D ? false : this.level.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS; // Paper - use distanceToSqr + } + // Leaves end - strip raytracing } } diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java index 2ee9e8e3c1a28c1823de8e1fe421cc1f3e72f384..49670b17d8c3d0f903b823e78531d2d18cf77e3b 100644 --- a/src/main/java/net/minecraft/world/level/BlockGetter.java +++ b/src/main/java/net/minecraft/world/level/BlockGetter.java @@ -73,6 +73,16 @@ public interface BlockGetter extends LevelHeightAccessor { }); } + // Leaves start - broken down variant of below rayTraceBlock, used by World#rayTraceDirect + default net.minecraft.world.phys.BlockHitResult.Type rayTraceBlockDirect(Vec3 vec3d, Vec3 vec3d1, BlockPos blockposition, BlockState iblockdata, net.minecraft.world.phys.shapes.CollisionContext voxelshapecoll) { + if (iblockdata.isAir()) return null; // Tuinity - optimise air cases + VoxelShape voxelshape = ClipContext.Block.COLLIDER.get(iblockdata, this, blockposition, voxelshapecoll); + net.minecraft.world.phys.BlockHitResult movingobjectpositionblock = this.clipWithInteractionOverride(vec3d, vec3d1, blockposition, voxelshape, iblockdata); + + return movingobjectpositionblock == null ? null : movingobjectpositionblock.getType(); + } + // Leaves end - broken down variant of below rayTraceBlock, used by World#rayTraceDirect + // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) { // Paper start - Prevent raytrace from loading chunks diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 31f0034115a88a42b18e0b838eab8b801473bbef..8cadc9655b8876ede4ec4d2b09198445b56fde29 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -415,6 +415,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return null; } + // Leaves start - broken down method of raytracing for EntityLiving#hasLineOfSight, replaces IBlockAccess#rayTrace(RayTrace) + public net.minecraft.world.phys.BlockHitResult.Type rayTraceDirect(net.minecraft.world.phys.Vec3 vec3d, net.minecraft.world.phys.Vec3 vec3d1, net.minecraft.world.phys.shapes.CollisionContext voxelshapecoll) { + // most of this code comes from IBlockAccess#a(RayTrace, BiFunction, Function), but removes the needless functions + if (vec3d.equals(vec3d1)) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + double endX = Mth.lerp(-1.0E-7D, vec3d1.x, vec3d.x); + double endY = Mth.lerp(-1.0E-7D, vec3d1.y, vec3d.y); + double endZ = Mth.lerp(-1.0E-7D, vec3d1.z, vec3d.z); + + double startX = Mth.lerp(-1.0E-7D, vec3d.x, vec3d1.x); + double startY = Mth.lerp(-1.0E-7D, vec3d.y, vec3d1.y); + double startZ = Mth.lerp(-1.0E-7D, vec3d.z, vec3d1.z); + + int currentX = Mth.floor(startX); + int currentY = Mth.floor(startY); + int currentZ = Mth.floor(startZ); + + BlockPos.MutableBlockPos currentBlock = new BlockPos.MutableBlockPos(currentX, currentY, currentZ); + + LevelChunk chunk = this.getChunkIfLoaded(currentBlock); + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + net.minecraft.world.phys.BlockHitResult.Type initialCheck = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getBlockState(currentBlock), voxelshapecoll); + + if (initialCheck != null) { + return initialCheck; + } + + double diffX = endX - startX; + double diffY = endY - startY; + double diffZ = endZ - startZ; + + int xDirection = Mth.sign(diffX); + int yDirection = Mth.sign(diffY); + int zDirection = Mth.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 - Mth.frac(startX) : Mth.frac(startX)); + double normalizedYDirection = normalizedY * (yDirection > 0 ? 1.0D - Mth.frac(startY) : Mth.frac(startY)); + double normalizedZDirection = normalizedZ * (zDirection > 0 ? 1.0D - Mth.frac(startZ) : Mth.frac(startZ)); + + net.minecraft.world.phys.BlockHitResult.Type result; + + do { + if (normalizedXDirection > 1.0D && normalizedYDirection > 1.0D && normalizedZDirection > 1.0D) { + return net.minecraft.world.phys.BlockHitResult.Type.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.set(currentX, currentY, currentZ); + if (chunk.getPos().x != currentBlock.getX() >> 4 || chunk.getPos().z != currentBlock.getZ() >> 4) { + chunk = this.getChunkIfLoaded(currentBlock); + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + } + result = this.rayTraceBlockDirect(vec3d, vec3d1, currentBlock, chunk.getBlockState(currentBlock), voxelshapecoll); + } while (result == null); + + return result; + } + // Leaves end - broken down method of raytracing for EntityLiving#hasLineOfSight, replaces IBlockAccess#rayTrace(RayTrace) + public boolean isInWorldBounds(BlockPos pos) { return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - use better/optimized check } diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java index 00f49a8d6fa8fc460d276f31170d3379f06199bb..ce433db220fa43111ab72e27c932cacf2ed03178 100644 --- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java @@ -270,6 +270,11 @@ public final class LeavesConfig { enableSuffocationOptimization = getBoolean("settings.performance.enable-suffocation-optimization", enableSuffocationOptimization); } + public static boolean entityStripRaytracing = true; + private static void entityStripRaytracing() { + entityStripRaytracing = getBoolean("settings.performance.strip-raytracing-for-entity", entityStripRaytracing); + } + public static final class WorldConfig { public final String worldName;