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 8f9bbe88827b6697762f4d43dce1da3986a72abb..455d4f52dc4483c00a348e2833dfd99b1ece80f3 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -3592,7 +3592,13 @@ public abstract class LivingEntity extends Entity { 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 d1eefa6ef3e9abfe7af4d8310aa64465fa2d5463..c91735828dc99af0b880a5a105025b4294c487a7 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 fd18fb454263893d404979a9c9af860ee2ba9a3a..1bd4a181ccf82c687f58b8033683f15afbc1f6cd 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -411,6 +411,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 6091a783878f929edfb87cf88963590538c72634..76c4110c54c8a883fd015a434c7b101fa3fbb18b 100644 --- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java @@ -253,6 +253,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;