diff --git a/docs/MODIFICATION.md b/docs/MODIFICATION.md index 2ab4356f..4559379d 100644 --- a/docs/MODIFICATION.md +++ b/docs/MODIFICATION.md @@ -27,11 +27,19 @@ Leaves Modification ## Performance -> All of it will have configuration -> Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish) -> Powered by [Purpur](https://github.com/PurpurMC/Purpur) +> All of it will have configuration -- Optimize mob spawning (Powered by Pufferfish) -- Don't send useless entity packets (Powered by Purpur) -- Multithreaded Tracker (Powered by Pufferfish) -- Fix Paper#6045 (Powered by Pufferfish) \ No newline at end of file +> Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish) +- Optimize mob spawning +- Multithreaded Tracker +- Fix Paper#6045 +- Optimize entity coordinate key +- Optimize suffocation +- Strip raytracing for entity +- Optimize Spooky Season check +- Optimize Chunk ticking +- Skip POI finding in vehicle +- Optimize entity target finding + +> Powered by [Purpur](https://github.com/PurpurMC/Purpur) +- Don't send useless entity packets \ No newline at end of file diff --git a/docs/MODIFICATION_cn.md b/docs/MODIFICATION_cn.md index 6f7492f0..1c757c71 100644 --- a/docs/MODIFICATION_cn.md +++ b/docs/MODIFICATION_cn.md @@ -27,11 +27,19 @@ Leaves Modification ## 性能 -> 所有的性能内容都会存在配置项 -> Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish) -> Powered by [Purpur](https://github.com/PurpurMC/Purpur) +> 所有的性能内容都会存在配置项 -- 生物生成优化 (Powered by Pufferfish) -- 减少不必要的包发送 (Powered by Purpur) -- 异步实体追踪 (Powered by Pufferfish) -- 修复Paper#6045 (Powered by Pufferfish) \ No newline at end of file +> Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish) +- 生物生成优化 +- 异步实体追踪 +- 修复Paper#6045 +- 实体坐标键优化 +- 窒息检测优化 +- 实体射线优化 +- 万圣节检测优化 +- 区块刻优化 +- 跳过矿车中实体的路径搜索 +- 实体目标检测优化 + +> Powered by [Purpur](https://github.com/PurpurMC/Purpur) +- 减少不必要的包发送 diff --git a/patches/server/0023-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch b/patches/server/0023-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch index 7a9fec5a..134a095c 100644 --- a/patches/server/0023-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch +++ b/patches/server/0023-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch @@ -6,14 +6,30 @@ Subject: [PATCH] Fix Paper#6045, block goal shouldn't load chunks This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 26bf383caea68834c654b25653ced9017f1b1b22..76f5953be1742d6168db9de2dd3d11ba68804e54 100644 +index 26bf383caea68834c654b25653ced9017f1b1b22..71e3c7fc5c071e83dfeca6954771e55946b7d533 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java @@ -119,6 +119,7 @@ public abstract class MoveToBlockGoal extends Goal { for(int m = 0; m <= l; m = m > 0 ? -m : 1 - m) { for(int n = m < l && m > -l ? l : 0; n <= l; n = n > 0 ? -n : 1 - n) { mutableBlockPos.setWithOffset(blockPos, m, k - 1, n); -+ if (!this.mob.level.hasChunkAt(mutableBlockPos)) continue; // Leaves - if this block isn't loaded, continue ++ if (top.leavesmc.leaves.LeavesConfig.fixPaper6045 && !this.mob.level.hasChunkAt(mutableBlockPos)) continue; // Leaves - if this block isn't loaded, continue if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level, mutableBlockPos)) { this.blockPos = mutableBlockPos; setTargetPosition(mutableBlockPos.immutable()); // Paper +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index c47adc2d9d98dd08798cc26b3293d6153a7080ec..c7dff544ec7fa3d4737c731efba70de170ef7d68 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -228,6 +228,11 @@ public final class LeavesConfig { + asyncEntityTracker = getBoolean("settings.performance.async-entity-tracker", asyncEntityTracker); + } + ++ public static boolean fixPaper6045 = true; ++ private static void fixPaper6045() { ++ fixPaper6045 = getBoolean("settings.performance.fix.fix-paper-6045", fixPaper6045); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0024-Optimize-entity-coordinate-key.patch b/patches/server/0024-Optimize-entity-coordinate-key.patch new file mode 100644 index 00000000..b5443e1c --- /dev/null +++ b/patches/server/0024-Optimize-entity-coordinate-key.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sun, 14 Aug 2022 08:17:28 +0800 +Subject: [PATCH] Optimize entity coordinate key + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java +index 7034af8ad42940c5af6b9032b9873ce36c55a2a7..6f28c6283f094cb72fec7f42b599b0c1f4963fbf 100644 +--- a/src/main/java/net/minecraft/server/MCUtil.java ++++ b/src/main/java/net/minecraft/server/MCUtil.java +@@ -209,7 +209,13 @@ public final class MCUtil { + } + + public static long getCoordinateKey(final Entity entity) { +- return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); ++ // Leaves start - eliminate double -> long cast in hotpath ++ if (top.leavesmc.leaves.LeavesConfig.optimizeEntityCoordinateKey) { ++ return ((long)(entity.blockPosition.getZ() >> 4) << 32) | ((entity.blockPosition.getX() >> 4) & 0xFFFFFFFFL); ++ } else { ++ return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); ++ } ++ // Leaves end - eliminate double -> long cast in hotpath + } + + public static long getCoordinateKey(final ChunkPos pair) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index eda98b85fb00fe7787d2f7a643c3854aa4b02fbf..1f1bed78e8d003cfd85bc5cf38014c3ddb3078d1 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -292,7 +292,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + public double yo; + public double zo; + private Vec3 position; +- private BlockPos blockPosition; ++ public BlockPos blockPosition; // Leaves - private -> public + private ChunkPos chunkPosition; + private Vec3 deltaMovement; + public float yRot; // Paper - private->public +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index c7dff544ec7fa3d4737c731efba70de170ef7d68..a3c400bc3ba55e286d05ad543d5bcb24008d5346 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -233,6 +233,11 @@ public final class LeavesConfig { + fixPaper6045 = getBoolean("settings.performance.fix.fix-paper-6045", fixPaper6045); + } + ++ public static boolean optimizeEntityCoordinateKey = true; ++ private static void optimizeEntityCoordinateKey() { ++ optimizeEntityCoordinateKey = getBoolean("settings.performance.optimize-entity-coordinate-key", optimizeEntityCoordinateKey); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0025-Optimize-suffocation.patch b/patches/server/0025-Optimize-suffocation.patch new file mode 100644 index 00000000..ae239c79 --- /dev/null +++ b/patches/server/0025-Optimize-suffocation.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sun, 14 Aug 2022 08:25:24 +0800 +Subject: [PATCH] Optimize suffocation + +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 2dee51917888e20768f434b8232430094028b516..8f9bbe88827b6697762f4d43dce1da3986a72abb 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -399,7 +399,7 @@ public abstract class LivingEntity extends Entity { + if (this.isAlive()) { + boolean flag = this instanceof net.minecraft.world.entity.player.Player; + +- if (this.isInWall()) { ++ if ((!top.leavesmc.leaves.LeavesConfig.enableSuffocationOptimization || (tickCount % 10 == 0 && couldPossiblyBeHurt(1.0F))) && this.isInWall()) { // Leaves - optimize suffocation + this.hurt(DamageSource.IN_WALL, 1.0F); + } else if (flag && !this.level.getWorldBorder().isWithinBounds(this.getBoundingBox())) { + double d0 = this.level.getWorldBorder().getDistanceToBorder(this) + this.level.getWorldBorder().getDamageSafeZone(); +@@ -1313,6 +1313,15 @@ public abstract class LivingEntity extends Entity { + return this.getHealth() <= 0.0F; + } + ++ // Leaves start - optimize suffocation ++ public boolean couldPossiblyBeHurt(float amount) { ++ if ((float) this.invulnerableTime > (float) this.invulnerableDuration / 2.0F && amount <= this.lastHurt) { ++ return false; ++ } ++ return true; ++ } ++ // Leaves end - optimize suffocation ++ + @Override + public boolean hurt(DamageSource source, float amount) { + if (this.isInvulnerableTo(source)) { +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index a3c400bc3ba55e286d05ad543d5bcb24008d5346..aa598fdf938889eb55c00bcbd733858890788d76 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -238,6 +238,11 @@ public final class LeavesConfig { + optimizeEntityCoordinateKey = getBoolean("settings.performance.optimize-entity-coordinate-key", optimizeEntityCoordinateKey); + } + ++ public static boolean enableSuffocationOptimization = true; ++ private static void enableSuffocationOptimization() { ++ enableSuffocationOptimization = getBoolean("settings.performance.enable-suffocation-optimization", enableSuffocationOptimization); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0026-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch b/patches/server/0026-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch new file mode 100644 index 00000000..5810b6db --- /dev/null +++ b/patches/server/0026-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch @@ -0,0 +1,159 @@ +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 aa598fdf938889eb55c00bcbd733858890788d76..c37308f2973b09f0efc3d4ccb012c2792e63f939 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -243,6 +243,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; diff --git a/patches/server/0027-Only-check-for-spooky-season-once-an-hour.patch b/patches/server/0027-Only-check-for-spooky-season-once-an-hour.patch new file mode 100644 index 00000000..f9e15a44 --- /dev/null +++ b/patches/server/0027-Only-check-for-spooky-season-once-an-hour.patch @@ -0,0 +1,62 @@ +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:35:42 +0800 +Subject: [PATCH] Only check for spooky season once an hour + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +index 50d4595b81f24949011c7565c5e3fc8c26c86019..8de1653e3fbf29e9de550a1976344bd8967485e3 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +@@ -253,13 +253,30 @@ public class Bat extends AmbientCreature { + } + } + ++ // Leaves start - only check for spooky season once an hour ++ private static boolean isSpookySeason = false; ++ private static final int ONE_HOUR = 20 * 60 * 60; ++ private static int lastSpookyCheck = -ONE_HOUR; + private static boolean isHalloween() { +- LocalDate localdate = LocalDate.now(); +- int i = localdate.get(ChronoField.DAY_OF_MONTH); +- int j = localdate.get(ChronoField.MONTH_OF_YEAR); ++ if (top.leavesmc.leaves.LeavesConfig.checkSpookySeasonOnceAnHour) { ++ if (net.minecraft.server.MinecraftServer.currentTick - lastSpookyCheck > ONE_HOUR) { ++ LocalDate localdate = LocalDate.now(); ++ int i = localdate.get(ChronoField.DAY_OF_MONTH); ++ int j = localdate.get(ChronoField.MONTH_OF_YEAR); ++ ++ isSpookySeason = j == 10 && i >= 20 || j == 11 && i <= 3; ++ lastSpookyCheck = net.minecraft.server.MinecraftServer.currentTick; ++ } ++ return isSpookySeason; ++ } else { ++ LocalDate localdate = LocalDate.now(); ++ int i = localdate.get(ChronoField.DAY_OF_MONTH); ++ int j = localdate.get(ChronoField.MONTH_OF_YEAR); + +- return j == 10 && i >= 20 || j == 11 && i <= 3; ++ return j == 10 && i >= 20 || j == 11 && i <= 3; ++ } + } ++ // Leaves end - only check for spooky season once an hour + + @Override + protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index c37308f2973b09f0efc3d4ccb012c2792e63f939..89623a5cd22b57733342a5b03cc4a21dca4eac33 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -248,6 +248,11 @@ public final class LeavesConfig { + entityStripRaytracing = getBoolean("settings.performance.strip-raytracing-for-entity", entityStripRaytracing); + } + ++ public static boolean checkSpookySeasonOnceAnHour = true; ++ private static void checkSpookySeasonOnceAnHour() { ++ checkSpookySeasonOnceAnHour = getBoolean("settings.performance.check-spooky-season-once-an-hour", checkSpookySeasonOnceAnHour); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0028-Move-ThreadUnsafeRandom-Initialization.patch b/patches/server/0028-Move-ThreadUnsafeRandom-Initialization.patch new file mode 100644 index 00000000..98aa0c16 --- /dev/null +++ b/patches/server/0028-Move-ThreadUnsafeRandom-Initialization.patch @@ -0,0 +1,46 @@ +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:54:33 +0800 +Subject: [PATCH] Move ThreadUnsafeRandom Initialization + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 82e3070ad9478a629bee45c8089d68d467ed9749..bc185f733d7543bb12c8f1f277197810154f739a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -757,7 +757,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + // Paper start - optimise random block ticking + private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); +- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); ++ // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); // Leaves - moved to super + // Paper end + + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 1bd4a181ccf82c687f58b8033683f15afbc1f6cd..42aa3014ceb5248a4cc5195b7c1873e425c8cdf0 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -272,6 +272,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + public abstract ResourceKey getTypeKey(); + ++ protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); // Leaves - move thread unsafe random initialization ++ + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper +@@ -361,6 +363,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + this.entitySliceManager = new io.papermc.paper.world.EntitySliceManager((ServerLevel)this); // Paper + } + ++ // Leaves start - thread unsafe random get ++ public io.papermc.paper.util.math.ThreadUnsafeRandom getThreadUnsafeRandom() { ++ return randomTickRandom; ++ } ++ // Leaves end - thread unsafe random get ++ + // Paper start + // ret true if no collision + public final boolean checkEntityCollision(BlockState data, Entity source, CollisionContext voxelshapedcollision, diff --git a/patches/server/0029-Optimize-random-calls-in-chunk-ticking.patch b/patches/server/0029-Optimize-random-calls-in-chunk-ticking.patch new file mode 100644 index 00000000..9bef85be --- /dev/null +++ b/patches/server/0029-Optimize-random-calls-in-chunk-ticking.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sun, 14 Aug 2022 11:01:17 +0800 +Subject: [PATCH] Optimize random calls in chunk ticking + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index bcc24c563cc8d35bffb594b11954e916711ce971..b653393ff465f5b0448f62e57697ae8c5d920425 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -967,6 +967,11 @@ public class ServerChunkCache extends ChunkSource { + ProfilerFiller gameprofilerfiller = this.level.getProfiler(); + + gameprofilerfiller.push("pollingChunks"); ++ // Leaves start - reset ice & snow tick random ++ if (top.leavesmc.leaves.LeavesConfig.optimizeChunkTicking) { ++ this.level.resetIceAndSnowTick(); ++ } ++ // Leaves end - reset ice & snow tick random + int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + boolean flag1 = level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index bc185f733d7543bb12c8f1f277197810154f739a..bb360a8a54fa4efe1cc6b672df09d4c0d6816d16 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -760,6 +760,13 @@ public class ServerLevel extends Level implements WorldGenLevel { + // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); // Leaves - moved to super + // Paper end + ++ // Leaves start - reset ice & snow tick random ++ private int currentIceAndSnowTick = 0; ++ protected void resetIceAndSnowTick() { ++ this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); ++ } ++ // Leaves end - reset ice & snow tick random ++ + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + ChunkPos chunkcoordintpair = chunk.getPos(); + boolean flag = this.isRaining(); +@@ -770,7 +777,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + gameprofilerfiller.push("thunder"); + final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change + +- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder ++ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && top.leavesmc.leaves.LeavesConfig.optimizeChunkTicking ? chunk.shouldDoLightning(this.random) : this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder // Leaves - replace random with shouldDoLightning + blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper + if (this.isRainingAt(blockposition)) { + DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); +@@ -794,7 +801,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.popPush("iceandsnow"); +- if (!this.paperConfig().environment.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow ++ if (!this.paperConfig().environment.disableIceAndSnow && top.leavesmc.leaves.LeavesConfig.optimizeChunkTicking ? (this.currentIceAndSnowTick++ & 15) == 0 : this.random.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking // Leaves - optimize further random ticking + // Paper start - optimise chunk ticking + this.getRandomBlockPosition(j, 0, k, 15, blockposition); + int normalY = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15) + 1; +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index 2292cb0e0c1a3e0ed34b941f028136bfb0bff13e..a6ea5fd73cb1f6b3c6c35d0cde331b6c37c1c770 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -94,6 +94,18 @@ public class LevelChunk extends ChunkAccess { + } + // Paper end + ++ // Leaves start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively ++ private int lightningTick; ++ // shouldDoLightning compiles down to 29 bytes, which with the default of 35 byte inlining should guarantee an inline ++ public final boolean shouldDoLightning(net.minecraft.util.RandomSource random) { ++ if (this.lightningTick-- <= 0) { ++ this.lightningTick = random.nextInt(this.level.spigotConfig.thunderChance) << 1; ++ return true; ++ } ++ return false; ++ } ++ // Leaves end - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively ++ + public LevelChunk(Level world, ChunkPos pos) { + this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null); + } +@@ -124,6 +136,11 @@ public class LevelChunk extends ChunkAccess { + this.fluidTicks = fluidTickScheduler; + // CraftBukkit start + this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); ++ // Leaves start - initialize lightning tick ++ if (top.leavesmc.leaves.LeavesConfig.optimizeChunkTicking) { ++ this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; ++ } ++ // Leaves end - initialize lightning tick + } + + public org.bukkit.Chunk bukkitChunk; +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index 89623a5cd22b57733342a5b03cc4a21dca4eac33..15d78e6fcc58a06f5d89c06ed1b87772f8b59eed 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 { + checkSpookySeasonOnceAnHour = getBoolean("settings.performance.check-spooky-season-once-an-hour", checkSpookySeasonOnceAnHour); + } + ++ public static boolean optimizeChunkTicking = true; ++ private static void optimizeChunkTicking() { ++ optimizeChunkTicking = getBoolean("settings.performance.optimize-chunk-ticking", optimizeChunkTicking); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0030-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/server/0030-Skip-POI-finding-if-stuck-in-vehicle.patch new file mode 100644 index 00000000..ca2c35c8 --- /dev/null +++ b/patches/server/0030-Skip-POI-finding-if-stuck-in-vehicle.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sun, 14 Aug 2022 11:18:44 +0800 +Subject: [PATCH] Skip POI finding if stuck in vehicle + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +index 43243537b765a2d270be6de3f053fea77ff67d18..7d8a137068ab2b33690c369f4da46e90b5f98e2e 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +@@ -72,6 +72,7 @@ public class AcquirePoi extends Behavior { + @Override + protected void start(ServerLevel world, PathfinderMob entity, long time) { + this.nextScheduledStart = time + 20L + (long)world.getRandom().nextInt(20); ++ if (top.leavesmc.leaves.LeavesConfig.skipPOIFindingInVehicle && entity.getNavigation().isStuck()) this.nextScheduledStart += 200L; // Leaves - wait an additional 10s to check again if they're stuck + PoiManager poiManager = world.getPoiManager(); + this.batchCache.long2ObjectEntrySet().removeIf((entry) -> { + return !entry.getValue().isStillValid(time); +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index 15d78e6fcc58a06f5d89c06ed1b87772f8b59eed..f2591cdffad6ecd17aa192337be6d83cec7dbff2 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -258,6 +258,11 @@ public final class LeavesConfig { + optimizeChunkTicking = getBoolean("settings.performance.optimize-chunk-ticking", optimizeChunkTicking); + } + ++ public static boolean skipPOIFindingInVehicle = true; ++ private static void skipPOIFindingInVehicle() { ++ skipPOIFindingInVehicle = getBoolean("settings.performance.skip-poi-find-in-vehicle", skipPOIFindingInVehicle); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0031-Early-return-optimization-for-target-finding.patch b/patches/server/0031-Early-return-optimization-for-target-finding.patch new file mode 100644 index 00000000..3136124e --- /dev/null +++ b/patches/server/0031-Early-return-optimization-for-target-finding.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sun, 14 Aug 2022 17:16:19 +0800 +Subject: [PATCH] Early return optimization for target finding + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +index a7575b5ef56af6f53448d391abb4956e130148ca..e2764cbc888be39943728ff810e1e44bc8be2af7 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java ++++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +@@ -75,9 +75,17 @@ public class TargetingConditions { + } + + if (this.range > 0.0D) { ++ // Leaves start - check range before getting visibility ++ double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); ++ if (top.leavesmc.leaves.LeavesConfig.entityTargetFindingOptimization) { ++ double followRangeRaw = this.useFollowRange ? this.getFollowRange(baseEntity) : this.range; ++ if (f > followRangeRaw * followRangeRaw) { // the actual follow range will always be this value or smaller, so if the distance is larger then it never will return true after getting invis ++ return false; ++ } ++ } + double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D; + double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper +- double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); ++ // Leaves end - check range before getting visibility + if (f > e * e) { + return false; + } +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index f2591cdffad6ecd17aa192337be6d83cec7dbff2..aa84bb020997abc34f855d45f348a9d69da99575 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -262,6 +262,11 @@ public final class LeavesConfig { + private static void skipPOIFindingInVehicle() { + skipPOIFindingInVehicle = getBoolean("settings.performance.skip-poi-find-in-vehicle", skipPOIFindingInVehicle); + } ++ ++ public static boolean entityTargetFindingOptimization = true; ++ private static void entityTargetFindingOptimization() { ++ entityTargetFindingOptimization = getBoolean("settings.performance.entity-target-find-optimization", entityTargetFindingOptimization); ++ } + + public static final class WorldConfig { +