From 510ddf3bbcf88e5b401ba42db2a3ca35d9fcbbb6 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sun, 15 Jun 2025 10:40:02 +0900 Subject: [PATCH 01/26] fix FasterRandomSource#next generate same random number (#374) --- .../dreeam/leaf/util/math/random/FasterRandomSource.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java index ee6d5dc5..301a66ee 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java @@ -56,11 +56,7 @@ public class FasterRandomSource implements BitRandomSource { @Override public final int next(int bits) { - if (useDirectImpl) { - return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); - } - - return (int) ((seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); + return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); } public static class FasterRandomSourcePositionalRandomFactory implements PositionalRandomFactory { From 0e1ff0ecd26acc6d18f9cee15a7e13164c9ca7e2 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Sun, 15 Jun 2025 19:38:04 +1400 Subject: [PATCH 02/26] Port random generator fix from 1.21.4 --- .../dreeam/leaf/util/math/random/FasterRandomSource.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java index ee6d5dc5..301a66ee 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java @@ -56,11 +56,7 @@ public class FasterRandomSource implements BitRandomSource { @Override public final int next(int bits) { - if (useDirectImpl) { - return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); - } - - return (int) ((seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); + return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); } public static class FasterRandomSourcePositionalRandomFactory implements PositionalRandomFactory { From 18ddfa97c63aafbd7bf25f563937aec81a85ff0b Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:10:50 +0800 Subject: [PATCH 03/26] [ci skip] Update README_CN.md --- public/readme/README_CN.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/readme/README_CN.md b/public/readme/README_CN.md index 74cba815..1ecc4200 100644 --- a/public/readme/README_CN.md +++ b/public/readme/README_CN.md @@ -2,11 +2,11 @@
[![下载](https://img.shields.io/badge/releases-blue?label=%e4%b8%8b%e8%bd%bd&style=for-the-badge&colorA=19201a&colorB=298046)](https://www.leafmc.one/zh/download)⠀ -[![Github Actions 构建](https://img.shields.io/github/actions/workflow/status/Winds-Studio/Leaf/build-1214.yml?label=%e6%9e%84%e5%bb%ba&style=for-the-badge&colorA=19201a&colorB=298046)](https://github.com/Winds-Studio/Leaf/actions)⠀ +[![Github Actions 构建](https://img.shields.io/github/actions/workflow/status/Winds-Studio/Leaf/build-1215.yml?label=%e6%9e%84%e5%bb%ba&style=for-the-badge&colorA=19201a&colorB=298046)](https://github.com/Winds-Studio/Leaf/actions)⠀ ![QQ](https://img.shields.io/badge/619278377-blue?label=QQ%e7%be%a4&style=for-the-badge&colorA=19201a&colorB=298046) [![文档](https://img.shields.io/badge/leafmc.one/zh/docs-blue?label=%e6%96%87%e6%a1%a3&style=for-the-badge&colorA=19201a&colorB=298046)](https://www.leafmc.one/zh/docs) -**Leaf** 是一个基于 [Paper](https://papermc.io/) 的分支,专为高自定义和高性能而设计,基于 [Gale](https://github.com/Dreeam-qwq/Gale) 之上,并融合了其他核心的优化和修复。 +**Leaf** 是一个基于 [Paper](https://papermc.io/) 的分支,专为高自定义和高性能而设计。
> [!WARNING] @@ -15,7 +15,7 @@ [English](../../README.md) | **中文** ## 🍃 特点 -- **基于 [Gale](https://github.com/Dreeam-qwq/Gale)**,以获得更好的性能 +- **基于 [Paper](https://papermc.io/)**,以获得更好的性能和灵活的 API - **异步**寻路、生物生成和实体追踪 - **大量优化**融合自 [其他核心](#-致谢) 和我们自己的的补丁 - **完全兼容** Spigot 和 Paper 插件 @@ -65,7 +65,7 @@ cn.dreeam.leaf leaf-api - 1.21.4-R0.1-SNAPSHOT + 1.21.5-R0.1-SNAPSHOT provided ``` @@ -78,7 +78,7 @@ repositories { } dependencies { - compileOnly("cn.dreeam.leaf:leaf-api:1.21.4-R0.1-SNAPSHOT") + compileOnly("cn.dreeam.leaf:leaf-api:1.21.5-R0.1-SNAPSHOT") } java { @@ -136,4 +136,4 @@ If you want to find a cheaper, high performance, stable, lower latency host, the YourKit 通过创新和智能的工具支持开源项目,用于监控和分析 Java 和 .NET 应用程序。 YourKit 是 [YourKit Java Profiler](https://www.yourkit.com/java/profiler/)、 [YourKit .NET Profiler](https://www.yourkit.com/dotnet-profiler/) 和 -[YourKit YouMonitor](https://www.yourkit.com/youmonitor/) 的创造者。 \ No newline at end of file +[YourKit YouMonitor](https://www.yourkit.com/youmonitor/) 的创造者。 From 04543a97f309e519cea0363af76058095dddda6e Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Mon, 16 Jun 2025 20:28:09 +0900 Subject: [PATCH 04/26] cleanup & remove threshold in async target finding --- .../features/0149-Async-target-finding.patch | 409 +++++++----------- .../features/0191-Paw-optimization.patch | 6 +- .../leaf/async/ai/AsyncGoalExecutor.java | 75 +--- .../dreeam/leaf/async/ai/AsyncGoalThread.java | 19 +- .../modules/async/AsyncTargetFinding.java | 7 +- 5 files changed, 189 insertions(+), 327 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0149-Async-target-finding.patch b/leaf-server/minecraft-patches/features/0149-Async-target-finding.patch index 86cbd622..8d3d7b06 100644 --- a/leaf-server/minecraft-patches/features/0149-Async-target-finding.patch +++ b/leaf-server/minecraft-patches/features/0149-Async-target-finding.patch @@ -134,7 +134,7 @@ index 33dd16a26edd2974f04d9a868d3e58e8e3060032..eb0589b203bcf72cd24bb37f2c448c23 // Gale start - Pufferfish - SIMD support diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e..7955a8fa9c4de139b24c9d53018b055ff4008e02 100644 +index fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e..53ea97c91684e9a0a3ed9f94ac15c242a43434ec 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -177,7 +177,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -163,26 +163,13 @@ index fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e..7955a8fa9c4de139b24c9d53018b055f public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately -@@ -336,6 +346,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); - } - -+ // Leaf start - Async target finding -+ public final void leafMidTickTasks() { -+ if (this.asyncGoalExecutor != null) this.asyncGoalExecutor.midTick(); -+ } -+ // Leaf end - Async target finding -+ - @Override - public final ChunkAccess moonrise$syncLoadNonFull(final int chunkX, final int chunkZ, final net.minecraft.world.level.chunk.status.ChunkStatus status) { - return this.moonrise$getChunkTaskScheduler().syncLoadNonFull(chunkX, chunkZ, status); -@@ -712,6 +728,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -712,6 +722,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle this.realPlayers = Lists.newArrayList(); // Leaves - skip this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.dreeam.leaf.async.world.SparklyPaperServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking + // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ this.asyncGoalExecutor = new org.dreeam.leaf.async.ai.AsyncGoalExecutor(server.asyncGoalThread, this); ++ this.asyncGoalExecutor = new org.dreeam.leaf.async.ai.AsyncGoalExecutor(this); + } else { + this.asyncGoalExecutor = null; + } @@ -190,39 +177,8 @@ index fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e..7955a8fa9c4de139b24c9d53018b055f } // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads -@@ -985,12 +1008,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - this.moonrise$midTickTasks(); // Paper - rewrite chunk system - // Gale end - Airplane - remove lambda from ticking guard - copied from guardEntityTick -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - } - } - } - ); - this.tickBlockEntities(); -+ if (this.asyncGoalExecutor != null) this.asyncGoalExecutor.tick(); // Leaf - Async target finding - } - - // Paper - rewrite chunk system -@@ -1463,6 +1488,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - // Paper end - rewrite chunk system - -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - - private void tickBlock(BlockPos pos, Block block) { -@@ -1479,6 +1505,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - // Paper end - rewrite chunk system - -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - - // Paper start - log detailed entity tick information diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java -index 9bee3c8e13b1d5d66139ed793fcd9bb154987cd0..7c095fd1d117bc0eeb18799943f1c1442219fd73 100644 +index 9bee3c8e13b1d5d66139ed793fcd9bb154987cd0..38b9931def2d407a3faa855db564e1d9ec1e636c 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java @@ -144,6 +144,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @@ -238,68 +194,39 @@ index 9bee3c8e13b1d5d66139ed793fcd9bb154987cd0..7c095fd1d117bc0eeb18799943f1c144 protected Mob(EntityType entityType, Level level) { super(entityType, level); -@@ -225,12 +231,22 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - } - // Paper end - Skip AI during inactive ticks for non-aware mobs - boolean isThrottled = org.dreeam.leaf.config.modules.opt.ThrottleInactiveGoalSelectorTick.enabled && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking -+ // Leaf start - Async target finding -+ boolean running = this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1; -+ this.tickingTarget = false; - if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking - this.goalSelector.tick(); - } -+ this.tickingTarget = true; +@@ -231,6 +237,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority this.targetSelector.tick(); } ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (!running && (this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1)) { -+ ((ServerLevel) this.level()).asyncGoalExecutor.submit(this.getId()); -+ } ++ ((ServerLevel) this.level()).asyncGoalExecutor.tickMob(this); + } + // Leaf end - Async target finding } // Paper end -@@ -900,17 +916,29 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - // Paper end - Allow nerfed mobs to jump and float - this.sensing.tick(); - int i = this.tickCount + this.getId(); -+ // Leaf start - Async target finding -+ boolean running = this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1; - if (i % 2 != 0 && this.tickCount > 1) { -+ this.tickingTarget = true; - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tickRunningGoals(false); -+ this.tickingTarget = false; - if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.goalSelector.tickRunningGoals(false); - } else { -+ this.tickingTarget = true; - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tick(); -+ this.tickingTarget = false; +@@ -911,6 +922,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.goalSelector.tick(); } ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (!running && (this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1)) { -+ ((ServerLevel) this.level()).asyncGoalExecutor.submit(this.getId()); -+ } ++ ((ServerLevel) this.level()).asyncGoalExecutor.tickMob(this); + } + // Leaf end - Async target finding this.navigation.tick(); this.customServerAiStep((ServerLevel)this.level()); diff --git a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java -index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d773403d0716f6 100644 +index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..22f052d02ccf22f22894a0b236af1b95c8d65e97 100644 --- a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java +++ b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java @@ -67,15 +67,24 @@ public class AvoidEntityGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async Avoid Entity Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (!poll()) { + getNearestEntityAsync(); @@ -313,11 +240,11 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d77340 this.mob, this.mob.getX(), - this.mob.getY(), -+ this.mob.getEyeY(), // Leaf - Async Avoid Entity Finding ++ this.mob.getEyeY(), // Leaf - Async target finding this.mob.getZ() ); + } -+ // Leaf end - Async Avoid Entity Finding ++ // Leaf end - Async target finding if (this.toAvoid == null) { return false; } else { @@ -325,7 +252,7 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d77340 } } -+ // Leaf start - Async Avoid Entity Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -353,20 +280,20 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d77340 + z + ); + } -+ // Leaf end - Async Avoid Entity Finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return !this.pathNav.isDone(); diff --git a/net/minecraft/world/entity/ai/goal/BegGoal.java b/net/minecraft/world/entity/ai/goal/BegGoal.java -index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375b12aca78 100644 +index 28ef40e8a645989ea181297069cf2bbe571f3082..661ff2379dca47162941f7ed2b6fb966a65f4ffc 100644 --- a/net/minecraft/world/entity/ai/goal/BegGoal.java +++ b/net/minecraft/world/entity/ai/goal/BegGoal.java @@ -27,8 +27,43 @@ public class BegGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.LOOK)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.wolf.getGoalCtx().result() instanceof Player target)) return false; + if (target == null) return false; @@ -390,11 +317,11 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375 + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -402,7 +329,7 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375 + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding this.player = this.level.getNearestPlayer(this.begTargeting, this.wolf); return this.player != null && this.playerHoldingInteresting(this.player); } @@ -411,16 +338,16 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375 } - private boolean playerHoldingInteresting(Player player) { -+ private static boolean playerHoldingInteresting(Player player) { // Leaf start - Async Target Finding - static ++ private static boolean playerHoldingInteresting(Player player) { // Leaf start - Async target finding - static for (InteractionHand interactionHand : InteractionHand.values()) { ItemStack itemInHand = player.getItemInHand(interactionHand); - if (itemInHand.is(Items.BONE) || this.wolf.isFood(itemInHand)) { -+ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { // Leaf end - Async Target Finding ++ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { // Leaf end - Async target finding return true; } } diff --git a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java -index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d657ccaa96c 100644 +index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..892e22b80d8c98ea2954b4024ba434da5a1abffa 100644 --- a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java @@ -52,6 +52,13 @@ public class CatLieOnBedGoal extends MoveToBlockGoal { @@ -428,18 +355,18 @@ index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d65 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); -+ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); // Leaf - Async search block - diff on change ++ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.CatLie; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java -index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d35a172a3b 100644 +index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..79e71a41245028042b8ac5a56cd39bd0940c37f5 100644 --- a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java @@ -44,14 +44,21 @@ public class CatSitOnBlockGoal extends MoveToBlockGoal { @@ -447,11 +374,11 @@ index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d3 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - if (!level.isEmptyBlock(pos.above())) { -+ if (!level.isEmptyBlock(pos.above())) { // Leaf - Async search block - diff on change ++ if (!level.isEmptyBlock(pos.above())) { // Leaf - Async target finding - diff on change return false; } else { - BlockState blockState = level.getBlockState(pos); -+ BlockState blockState = level.getBlockState(pos); // Leaf - Async search block - diff on change ++ BlockState blockState = level.getBlockState(pos); // Leaf - Async target finding - diff on change return blockState.is(Blocks.CHEST) ? ChestBlockEntity.getOpenCount(level, pos) < 1 : blockState.is(Blocks.FURNACE) && blockState.getValue(FurnaceBlock.LIT) @@ -459,22 +386,22 @@ index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d3 } } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.CatSit; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java -index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..92b6f87817aee8b277c07cf9138bf52aa20a82d6 100644 +index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..70c75c0b3be9de58e73663c194fd18e8cc2989e7 100644 --- a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java @@ -23,8 +23,47 @@ public class FollowBoatGoal extends Goal { this.mob = mob; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -500,10 +427,10 @@ index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..92b6f87817aee8b277c07cf9138bf52a + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding @Override public boolean canUse() { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -514,7 +441,7 @@ index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..92b6f87817aee8b277c07cf9138bf52a + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.mob.level().getEntitiesOfClass(AbstractBoat.class, this.mob.getBoundingBox().inflate(5.0)); boolean flag = false; @@ -523,19 +450,19 @@ index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..92b6f87817aee8b277c07cf9138bf52a } - return this.following != null && (Mth.abs(this.following.xxa) > 0.0F || Mth.abs(this.following.zza) > 0.0F) || flag; -+ return flag; // Leaf - Async Target Finding - move above ++ return flag; // Leaf - Async target finding - move above } @Override diff --git a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java -index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c9303917e194836 100644 +index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..66f69163ed8d36dcd0dec5603e72a88e8812d3e5 100644 --- a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java @@ -38,6 +38,15 @@ public class FollowMobGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async Follow Mob Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -543,7 +470,7 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 + getFollowingMobAsync(); + return false; + } -+ // Leaf end - Async Follow Mob Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.mob.level().getEntitiesOfClass(Mob.class, this.mob.getBoundingBox().inflate(this.areaSize), this.followPredicate); if (!entitiesOfClass.isEmpty()) { for (Mob mob : entitiesOfClass) { @@ -551,7 +478,7 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 return false; } -+ // Leaf start - Async Follow Mob Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Mob target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -579,20 +506,20 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 + return null; + }; + } -+ // Leaf end - Async Follow Mob Finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return this.followingMob != null && !this.navigation.isDone() && this.mob.distanceToSqr(this.followingMob) > this.stopDistance * this.stopDistance; diff --git a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java -index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270169330ef 100644 +index 3093f03d4f298bf39fec8bad2b6c22518774aea8..4eec8eda6ea1698529e0392bc75c07be5980f5fc 100644 --- a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java @@ -19,11 +19,56 @@ public class FollowParentGoal extends Goal { this.speedModifier = speedModifier; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.animal.getGoalCtx().result() instanceof Animal target)) return false; + var serverLevel = getServerLevel(animal); @@ -626,14 +553,14 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 + return target; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { if (this.animal.getAge() >= 0) { return false; } else { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -641,7 +568,7 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.animal .level() .getEntitiesOfClass((Class)this.animal.getClass(), this.animal.getBoundingBox().inflate(8.0, 4.0, 8.0)); @@ -649,12 +576,12 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 if (animal == null) { return false; } else if (d < 9.0) { -+ // Leaf - Async Target Finding - diff on change ++ // Leaf - Async target finding - diff on change return false; } else { this.parent = animal; diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb506310de8461 100644 +index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01c8bb0ba8 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -26,13 +26,23 @@ public class GoalSelector { @@ -703,13 +630,13 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); // Paper end - Perf: optimize goal types if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) { -@@ -85,7 +96,131 @@ public class GoalSelector { +@@ -85,7 +96,136 @@ public class GoalSelector { return true; } + // Leaf start - Async target finding + public final boolean poll() { -+ if (this.ctxGoals == null || ctx.wake != null) { ++ if (ctxState == -1 || this.ctxGoals == null || ctx.wake != null || ctxGoals.length == 0) { + return false; + } + if (ctxState == 0) { @@ -728,7 +655,12 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 + ctx.state = true; + } + -+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); ++ for (Goal.Flag flag : GOAL_FLAG_VALUES) { ++ var goal = this.lockedFlags.get(flag); ++ if (goal != null && !goal.isRunning()) { ++ this.lockedFlags.remove(flag); ++ } ++ } + + ctxIndex = 0; + ctx.state = true; @@ -776,7 +708,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 + if (!ctx.state) { + switch (goal.getGoal()) { + case net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal t -> t.poll(); -+ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal t -> t.poll(); ++ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal t -> t.poll(); + default -> {} + } + } @@ -821,12 +753,12 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 public void tick() { + // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (ctxState == -1) { -+ if (availableGoalsDirty || this.ctxGoals == null) { ++ if (this.ctxState == -1) { ++ if (this.availableGoalsDirty || this.ctxGoals == null) { + this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]); -+ availableGoalsDirty = false; ++ this.availableGoalsDirty = false; + } -+ ctxState = 0; ++ this.ctxState = 0; + } + return; + } @@ -835,7 +767,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams wrappedGoal.stop(); -@@ -116,6 +251,18 @@ public class GoalSelector { +@@ -116,6 +256,18 @@ public class GoalSelector { } public void tickRunningGoals(boolean tickAllRunning) { @@ -855,14 +787,14 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) { wrappedGoal.tick(); diff --git a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0bff40c42 100644 +index be59d0c27a83b329ec3f97c029cfb9c114e22472..888fd1919954acf3ec3c5d5a115dffc2e0fd3caf 100644 --- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java +++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java @@ -20,20 +20,83 @@ public class LlamaFollowCaravanGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + private @javax.annotation.Nullable Llama poll() { + if (!(this.llama.getGoalCtx().result() instanceof Llama target)) return null; + var serverLevel = getServerLevel(this.llama); @@ -911,13 +843,13 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 + return target; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { if (!this.llama.level().purpurConfig.llamaJoinCaravans || !this.llama.shouldJoinCaravan) return false; // Purpur - Llama API // Purpur - Config to disable Llama caravans if (!this.llama.isLeashed() && !this.llama.inCaravan()) { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + Llama llama = poll(); + double d = Double.MAX_VALUE; + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { @@ -928,20 +860,20 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 + d = this.llama.distanceToSqr(llama); + } + } else { -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entities = this.llama.level().getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0, 4.0, 9.0), entity1 -> { EntityType type = entity1.getType(); return type == EntityType.LLAMA || type == EntityType.TRADER_LLAMA; }); - Llama llama = null; - double d = Double.MAX_VALUE; -+ // Llama llama = null; // Leaf - Async Target Finding -+ // double d = Double.MAX_VALUE; // Leaf - Async Target Finding ++ // Llama llama = null; // Leaf - Async target finding ++ // double d = Double.MAX_VALUE; // Leaf - Async target finding for (Entity entity : entities) { Llama llama1 = (Llama)entity; - if (llama1.inCaravan() && !llama1.hasCaravanTail()) { -+ if (llama1.inCaravan() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change ++ if (llama1.inCaravan() && !llama1.hasCaravanTail()) { // Leaf - Async target finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { d = d1; @@ -950,7 +882,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 for (Entity entityx : entities) { Llama llama1 = (Llama)entityx; - if (llama1.isLeashed() && !llama1.hasCaravanTail()) { -+ if (llama1.isLeashed() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change ++ if (llama1.isLeashed() && !llama1.hasCaravanTail()) { // Leaf - Async target finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { d = d1; @@ -958,19 +890,19 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 } } } -+ } // Leaf - Async Target Finding ++ } // Leaf - Async target finding if (llama == null) { return false; diff --git a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java -index 6463c3c9b08d6058f2843c225b08a40fc30a960b..98c2b4a298ada4b02afa55f991791d8696702181 100644 +index 6463c3c9b08d6058f2843c225b08a40fc30a960b..126bd98bc5980a2f1177bd7c74918b86a1f5bdce 100644 --- a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java +++ b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java @@ -48,32 +48,79 @@ public class LookAtPlayerGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -1060,19 +992,19 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..98c2b4a298ada4b02afa55f991791d86 - } + }; } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding @Override public boolean canContinueToUse() { diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e7c93afca 100644 +index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad51691a42 100644 --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java @@ -41,8 +41,60 @@ public abstract class MoveToBlockGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP)); } -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof BlockPos blockPos1)) return false; + if (!this.mob.level().hasChunkAt(blockPos1) @@ -1117,15 +1049,15 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + TurtleToWater, + TurtleLay, + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + @Override public boolean canUse() { -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (poll()) { + return true; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding if (this.nextStartTick > 0) { this.nextStartTick--; return false; @@ -1133,12 +1065,12 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e } protected boolean findNearestBlock() { -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) { + getBlockAsync(); + return false; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding int i = this.searchRange; int i1 = this.verticalSearchRange; BlockPos blockPos = this.mob.blockPosition(); @@ -1146,7 +1078,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e return false; } -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected static @javax.annotation.Nullable BlockPos findNearestBlockAsync( + final TypeToCheck ty, + @org.jetbrains.annotations.Nullable final net.minecraft.world.level.block.Block toRemove, @@ -1180,11 +1112,11 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + private static boolean isWithinRestriction(float restrictRadius, BlockPos restrictCenter, BlockPos pos) { + return restrictRadius == -1.0F || restrictCenter.distSqr(pos) < restrictRadius * restrictRadius; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + protected abstract boolean isValidTarget(LevelReader level, BlockPos pos); + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected abstract TypeToCheck typeToCheck(); + + private static boolean isValidTargetAsync( @@ -1245,18 +1177,18 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + } + case null -> throw new IllegalStateException(); + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + } } diff --git a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java -index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80691ac1bc 100644 +index 3c274d917bca9de87abfb842f5f332e112a7a2d7..a3f96a6dac65a315842a4ae5de6c5ea04b7bd697 100644 --- a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java +++ b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java @@ -19,10 +19,20 @@ public class OfferFlowerGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async offer flower finding ++ // Leaf start - Async target finding if (!this.golem.level().isDay()) { return false; - } else if (this.golem.getRandom().nextInt(8000) != 0) { @@ -1270,7 +1202,7 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80 + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + getVillagerAsync(); + return false; -+ // Leaf end - Async offer flower finding ++ // Leaf end - Async target finding } else { this.villager = getServerLevel(this.golem) .getNearestEntity( @@ -1279,7 +1211,7 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80 } + -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.golem.getGoalCtx().result() instanceof Villager target)) return false; + var serverLevel = getServerLevel(this.golem); @@ -1306,13 +1238,13 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80 + z + ); + } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return this.tick > 0; diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700b4c8a02d 100644 +index c67a88c9c77ece7c85ffb169ac96da4f28291228..a70fbb0f613befcba5daa961d941c6d40c3c356f 100644 --- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java @@ -37,7 +37,14 @@ public class RemoveBlockGoal extends MoveToBlockGoal { @@ -1321,12 +1253,12 @@ index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700 return false; - } else if (this.nextStartTick > 0) { + } -+ // Leaf start - async search block ++ // Leaf start - Async target finding + if (poll()) { + this.nextStartTick = reducedTickDelay(20); + return true; + } -+ // Leaf end - async search block ++ // Leaf end - Async target finding + if (this.nextStartTick > 0) { this.nextStartTick--; return false; @@ -1336,27 +1268,27 @@ index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700 ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks return chunk != null - && chunk.getBlockState(pos).is(this.blockToRemove) -+ && chunk.getBlockState(pos).is(this.blockToRemove) // Leaf - Async search block - diff on change ++ && chunk.getBlockState(pos).is(this.blockToRemove) // Leaf - Async target finding - diff on change && chunk.getBlockState(pos.above()).isAir() && chunk.getBlockState(pos.above(2)).isAir(); } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.RemoveBlock; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java -index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50e9e62b34 100644 +index f88f618d34fb343b31de3af1a875d6633703df71..4bbd83c702a818b48313698919dc9a85392707f6 100644 --- a/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java @@ -36,12 +36,51 @@ public class TemptGoal extends Goal { this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity)); } -+ // Leaf start - Async Tempt Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -1375,14 +1307,14 @@ index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50 + .copy(); + ctx.wake = () -> serverLevel.getNearestPlayer(conditions, mob); + } -+ // Leaf end - Async Tempt Finding ++ // Leaf end - Async target finding @Override public boolean canUse() { if (this.calmDown > 0) { this.calmDown--; return false; } else { -+ // Leaf start - Async Tempt Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (poll()) { + if (this.player != null) { @@ -1400,28 +1332,19 @@ index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50 + return false; + } + } -+ // Leaf end - Async Tempt Finding ++ // Leaf end - Async target finding this.player = getServerLevel(this.mob) .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); // CraftBukkit start diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..c9750ad322ddaa9c457f0e652d87c7abf8559358 100644 +index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..6f55599d206d8d6cdabe4e2a00dddb98448e498f 100644 --- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -@@ -16,7 +16,7 @@ public class DefendVillageTargetGoal extends TargetGoal { - private final IronGolem golem; - @Nullable - private LivingEntity potentialTarget; -- private final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); -+ private static final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); // Leaf - Async Target Finding - static - - public DefendVillageTargetGoal(IronGolem golem) { - super(golem, false, true); @@ -24,8 +24,49 @@ public class DefendVillageTargetGoal extends TargetGoal { this.setFlags(EnumSet.of(Goal.Flag.TARGET)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); @@ -1451,7 +1374,7 @@ index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..c9750ad322ddaa9c457f0e652d87c7ab + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { @@ -1477,7 +1400,7 @@ index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..c9750ad322ddaa9c457f0e652d87c7ab @Override diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617aa32c3cc 100644 +index 25fe78116ce01eeefe5c958423734195d27302eb..b57f308963550584c73aaf8027061ac140a827a1 100644 --- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java @@ -73,6 +73,46 @@ public class HurtByTargetGoal extends TargetGoal { @@ -1485,7 +1408,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 double followDistance = this.getFollowDistance(); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followDistance, 10.0, followDistance); + -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var self = this.mob; + final var ctx = self.getGoalCtx(); @@ -1522,7 +1445,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 + }; + return; + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + List entitiesOfClass = this.mob .level() @@ -1532,7 +1455,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 mob = (Mob)var5.next(); if (this.mob != mob - && mob.getTarget() == null -+ && mob.getTarget() == null // Leaf - Async alert other - diff on change ++ && mob.getTarget() == null // Leaf - Async target finding - diff on change && (!(this.mob instanceof TamableAnimal) || ((TamableAnimal)this.mob).getOwner() == ((TamableAnimal)mob).getOwner()) && !mob.isAlliedTo(this.mob.getLastHurtByMob())) { if (this.toIgnoreAlert == null) { @@ -1541,7 +1464,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 boolean flag = false; - for (Class clazz : this.toIgnoreAlert) { -+ for (Class clazz : this.toIgnoreAlert) { // Leaf - Async alert other - diff on change ++ for (Class clazz : this.toIgnoreAlert) { // Leaf - Async target finding - diff on change if (mob.getClass() == clazz) { flag = true; break; @@ -1549,7 +1472,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 } } -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + public void poll() { + if (!(this.mob.getGoalCtx().result() instanceof List toAlert)) return; + LivingEntity lastHurtByMob = this.mob.getLastHurtByMob(); @@ -1577,20 +1500,20 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617 + } + } + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + protected void alertOther(Mob mob, LivingEntity target) { mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason } diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -index 85eae0a14f7a417dfd8c911079d05354a98e5834..f59d5c9be0eb10f5b5192442e1850900d71a31e9 100644 +index 85eae0a14f7a417dfd8c911079d05354a98e5834..0f20ad9dd776a057cf4a34fc9572181b0153b94f 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java @@ -41,8 +41,43 @@ public class NearestAttackableTargetGoal extends TargetG this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); @@ -1618,7 +1541,7 @@ index 85eae0a14f7a417dfd8c911079d05354a98e5834..f59d5c9be0eb10f5b5192442e1850900 + } + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { @@ -1635,13 +1558,13 @@ index 85eae0a14f7a417dfd8c911079d05354a98e5834..f59d5c9be0eb10f5b5192442e1850900 protected void findTarget() { ServerLevel serverLevel = getServerLevel(this.mob); + -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + this.findTargetAsync(); + this.target = null; + return; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + if (this.targetType != Player.class && this.targetType != ServerPlayer.class) { this.target = serverLevel.getNearestEntity( @@ -1689,14 +1612,14 @@ index abf57494950f55bbd75f335f26736cb9e703c197..efd2418f56c36e7850edde483a2a4906 } } diff --git a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java -index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc7fca2dc4 100644 +index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..08a09dea0dd377adca22b4432cf8f57c3122ec02 100644 --- a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java @@ -37,6 +37,27 @@ public class ResetUniversalAngerTargetGoal extends G this.lastHurtByPlayerTimestamp = this.mob.getLastHurtByMobTimestamp(); this.mob.forgetCurrentTargetAndRefreshUniversalAnger(); if (this.alertOthersOfSameType) { -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var mob = this.mob; + final var ctx = mob.getGoalCtx(); @@ -1716,7 +1639,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc + }; + return; + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding this.getNearbyMobsOfSameType() .stream() .filter(mob -> mob != this.mob) @@ -1724,7 +1647,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc super.start(); } -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + public void poll() { + if (!(this.mob.getGoalCtx().result() instanceof List toStop)) return; + for (var neutralMob : toStop) { @@ -1733,10 +1656,10 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc + } + } + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + private List getNearbyMobsOfSameType() { -+ // Leaf - Async alert other - diff on change ++ // Leaf - Async target finding - diff on change double attributeValue = this.mob.getAttributeValue(Attributes.FOLLOW_RANGE); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(attributeValue, 10.0, attributeValue); return this.mob.level().getEntitiesOfClass((Class)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS); @@ -1781,7 +1704,7 @@ index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..6fa0b8defbd1d06b3bf5d9b32ffd08f3 // Gale start - Petal - reduce line of sight cache lookups - merge sets int cached = this.seen.get(id); diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java -index 90452f0945e761077608692877677f522d38bccd..54044ff16e0c2963b2220e4fb4932fe0802aa178 100644 +index 90452f0945e761077608692877677f522d38bccd..0a6ca6eb0775a7bc9e3070b70444c170a6504eca 100644 --- a/net/minecraft/world/entity/animal/Fox.java +++ b/net/minecraft/world/entity/animal/Fox.java @@ -849,13 +849,18 @@ public class Fox extends Animal implements VariantHolder { @@ -1809,7 +1732,7 @@ index 90452f0945e761077608692877677f522d38bccd..54044ff16e0c2963b2220e4fb4932fe0 protected boolean isValidTarget(LevelReader level, BlockPos pos) { BlockState blockState = level.getBlockState(pos); - return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); -+ return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); // Leaf - Async search block - diff on change ++ return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); // Leaf - Async target finding - diff on change } @Override @@ -1818,24 +1741,24 @@ index 90452f0945e761077608692877677f522d38bccd..54044ff16e0c2963b2220e4fb4932fe0 super.start(); } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.FoxEat; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } class FoxFloatGoal extends FloatGoal { diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java -index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d99a1f6baebdc7c4a700e3fee30d1b52f3c1ac3d 100644 +index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..0fa38df5e2e11765a1d43ccc14b47730c83ae482 100644 --- a/net/minecraft/world/entity/animal/Panda.java +++ b/net/minecraft/world/entity/animal/Panda.java @@ -991,9 +991,18 @@ public class Panda extends Animal { @Override public boolean canUse() { -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -1846,12 +1769,12 @@ index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d99a1f6baebdc7c4a700e3fee30d1b52 + getLookAsync(); + return false; + } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding if (this.lookAt == null) { ServerLevel serverLevel = getServerLevel(this.mob); if (this.lookAtType == Player.class) { diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java -index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf19d89b673 100644 +index da5b32a17283e540615373097acc511d928aeff5..6211c6e41161852c06330f61b21969ac9a49cad8 100644 --- a/net/minecraft/world/entity/animal/Rabbit.java +++ b/net/minecraft/world/entity/animal/Rabbit.java @@ -642,7 +642,13 @@ public class Rabbit extends Animal implements VariantHolder { @@ -1859,13 +1782,13 @@ index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf1 } - return super.canUse(); -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (this.wantsToRaid && !this.canRaid) { + return super.canUse(); + } else { + return false; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } @Override @@ -1874,7 +1797,7 @@ index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf1 protected boolean isValidTarget(LevelReader level, BlockPos pos) { BlockState blockState = level.getBlockState(pos); - if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { -+ if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { // Leaf - Async search block - diff on change ++ if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { // Leaf - Async target finding - diff on change blockState = level.getBlockState(pos.above()); if (blockState.getBlock() instanceof CarrotBlock && ((CarrotBlock)blockState.getBlock()).isMaxAge(blockState)) { this.canRaid = true; @@ -1883,17 +1806,17 @@ index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf1 return false; } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.RaidGarden; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } public static enum Variant implements StringRepresentable { diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java -index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..c5f626dcfe724f8ed19303d305f6eb5cfcc0f0af 100644 +index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..a7c1f02e3e7346555d7f822acfb15b6dea312dd5 100644 --- a/net/minecraft/world/entity/animal/Turtle.java +++ b/net/minecraft/world/entity/animal/Turtle.java @@ -527,8 +527,15 @@ public class Turtle extends Animal { @@ -1901,15 +1824,15 @@ index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..c5f626dcfe724f8ed19303d305f6eb5c @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.getBlockState(pos).is(Blocks.WATER); -+ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async search block - diff on change ++ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.TurtleToWater; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class TurtleLayEggGoal extends MoveToBlockGoal { @@ -1918,20 +1841,20 @@ index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..c5f626dcfe724f8ed19303d305f6eb5c @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); -+ return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); // Leaf - Async search block - diff on change ++ return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); // Leaf - Async target finding - diff on change + } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.TurtleLay; } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java -index 7cb292de6b27fa4ba3c5fce526a4e939c576789f..68852158e2fd3c4ce241d722ac414d73ea3b8836 100644 +index 7cb292de6b27fa4ba3c5fce526a4e939c576789f..187707845c4ed8cc3be439a12633ba9c446d075f 100644 --- a/net/minecraft/world/entity/animal/Wolf.java +++ b/net/minecraft/world/entity/animal/Wolf.java @@ -672,7 +672,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder level.getNearestPlayer(cond, enderman); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding this.pendingTarget = getServerLevel(this.enderman).getNearestPlayer(this.startAggroTargetConditions.range(this.getFollowDistance()), this.enderman); return this.pendingTarget != null; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player player)) return false; + var serverLevel = getServerLevel(this.enderman); @@ -2004,13 +1927,13 @@ index c7897532163d4fdf5a82982f7d24a47dd61e3dfa..2986384389c1acd311f4367d62255083 + this.pendingTarget = player; + return true; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public void start() { this.aggroTime = this.adjustedTickDelay(5); diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java -index ae4ee948971e931e4fdc4ec2187f5182195c626c..f4fa19c6352e44a624e81dc201b1d7d710c2d9d2 100644 +index ae4ee948971e931e4fdc4ec2187f5182195c626c..041079bf35822e75b5464a6336f517b38cb19363 100644 --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java @@ -570,8 +570,15 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @@ -2018,31 +1941,23 @@ index ae4ee948971e931e4fdc4ec2187f5182195c626c..f4fa19c6352e44a624e81dc201b1d7d7 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); -+ return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); // Leaf - Async search block - diff on change ++ return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.Strider; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class StriderPathNavigation extends GroundPathNavigation { diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index ac7729d1caa80155697bfe0e8646e4eda5d1780e..2518ea7a9d2122ff55ab6546d21d7ed6cc933090 100644 +index ac7729d1caa80155697bfe0e8646e4eda5d1780e..c8872d7b8dbf368f401b6c36b8145c1d53ece0dd 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -1549,6 +1549,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - } - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - do not bother with condition work / make configurable - // Paper end - rewrite chunk system -+ ((ServerLevel) this).leafMidTickTasks(); // Leaf - Async target finding - } - } - this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals -@@ -1817,9 +1818,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1817,9 +1817,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate predicate) { diff --git a/leaf-server/minecraft-patches/features/0191-Paw-optimization.patch b/leaf-server/minecraft-patches/features/0191-Paw-optimization.patch index a735ae35..91d9e5fb 100644 --- a/leaf-server/minecraft-patches/features/0191-Paw-optimization.patch +++ b/leaf-server/minecraft-patches/features/0191-Paw-optimization.patch @@ -117,10 +117,10 @@ index c1efd558cfbfd2200295ef5755aa496e95deb7d7..15bbd1f7f2a90b4b5427026d622764bb this.tickChunks(l, list); // Gale - Purpur - remove vanilla profiler } finally { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 7955a8fa9c4de139b24c9d53018b055ff4008e02..eb849c57992658005e0f514c6f7923f8ca43bebf 100644 +index 53ea97c91684e9a0a3ed9f94ac15c242a43434ec..7cbcc2dd8533973108841d3989265a392a6f6214 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1521,13 +1521,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1511,13 +1511,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - log detailed entity tick information public void tickNonPassenger(Entity entity) { @@ -134,7 +134,7 @@ index 7955a8fa9c4de139b24c9d53018b055ff4008e02..eb849c57992658005e0f514c6f7923f8 entity.setOldPosAndRot(); entity.tickCount++; entity.totalEntityAge++; // Paper - age-like counter for all entities -@@ -1540,13 +1534,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1530,13 +1524,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (Entity entity1 : entity.getPassengers()) { this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java index 780e2678..371f54e5 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java @@ -1,6 +1,5 @@ package org.dreeam.leaf.async.ai; -import it.unimi.dsi.fastutil.ints.IntArrayList; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; @@ -10,85 +9,54 @@ import org.dreeam.leaf.config.modules.async.AsyncTargetFinding; import org.dreeam.leaf.util.queue.SpscIntQueue; import java.util.OptionalInt; -import java.util.concurrent.locks.LockSupport; public class AsyncGoalExecutor { protected static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal"); protected final SpscIntQueue queue; - protected final SpscIntQueue wake; - protected final IntArrayList submit; private final ServerLevel world; - private long midTickCount = 0L; - public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel world) { + public AsyncGoalExecutor(ServerLevel world) { this.world = world; this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize); - this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize); - this.submit = new IntArrayList(); } - boolean wake(int id) { - Entity entity = this.world.getEntities().get(id); - if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) { - return false; - } - mob.goalSelector.ctx.wake(); - mob.targetSelector.ctx.wake(); - return true; - } - - public final void submit(int entityId) { - this.submit.add(entityId); - } - - public final void tick() { - batchSubmit(); + boolean wakeAll() { + boolean success = false; while (true) { - OptionalInt result = this.wake.recv(); + OptionalInt result = queue.recv(); if (result.isEmpty()) { break; } int id = result.getAsInt(); - if (poll(id) && !this.queue.send(id)) { - do { - wake(id); - } while (poll(id)); - } + success = true; + wake(id); } + return success; } - private void batchSubmit() { - if (submit.isEmpty()) { + public void tickMob(Mob mob) { + if (!poll(mob)) { return; } - int[] raw = submit.elements(); - int size = submit.size(); - for (int i = 0; i < size; i++) { - int id = raw[i]; - if (poll(id) && !this.queue.send(id)) { - do { - wake(id); - } while (poll(id)); - } + int entityId = mob.getId(); + if (!this.queue.send(entityId)) { + do { + wake(entityId); + } while (poll(mob)); } - this.submit.clear(); } - public final void midTick() { - if (AsyncTargetFinding.threshold <= 0L || (midTickCount % AsyncTargetFinding.threshold) == 0L) { - batchSubmit(); - } - - midTickCount += 1; - } - - private boolean poll(int id) { + private void wake(int id) { Entity entity = this.world.getEntities().get(id); if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) { - return false; + return; } + mob.goalSelector.ctx.wake(); + mob.targetSelector.ctx.wake(); + } + private boolean poll(Mob mob) { try { mob.tickingTarget = true; boolean a = mob.targetSelector.poll(); @@ -97,8 +65,7 @@ public class AsyncGoalExecutor { return a || b; } catch (Exception e) { LOGGER.error("Exception while polling", e); - // retry - return true; + return false; } } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java index e989adbf..4012e4cf 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java @@ -22,26 +22,11 @@ public class AsyncGoalThread extends Thread { while (RUNNING) { boolean retry = false; for (ServerLevel level : server.getAllLevels()) { - var exec = level.asyncGoalExecutor; - while (true) { - OptionalInt result = exec.queue.recv(); - if (result.isEmpty()) { - break; - } - int id = result.getAsInt(); - retry = true; - if (exec.wake(id)) { - while (!exec.wake.send(id)) { - Thread.onSpinWait(); - } - } - } - - Thread.yield(); + retry |= level.asyncGoalExecutor.wakeAll(); } if (!retry) { - LockSupport.parkNanos(10_000L); + LockSupport.parkNanos(1_000_000L); } } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java index c22f1ce4..b4cea17b 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java @@ -15,7 +15,6 @@ public class AsyncTargetFinding extends ConfigModules { public static boolean searchBlock = true; public static boolean searchEntity = true; public static int queueSize = 4096; - public static long threshold = 10L; private static boolean asyncTargetFindingInitialized; @Override @@ -35,21 +34,17 @@ public class AsyncTargetFinding extends ConfigModules { enabled = config.getBoolean(getBasePath() + ".enabled", enabled); // Disable if parallel world ticking is enabled, as they are incompatible. if (enabled && SparklyPaperParallelWorldTicking.enabled) { - LeafConfig.LOGGER.warn("Async Target Finding is incompatible with Parallel World Ticking. Disabling Async Target Finding automatically."); + LeafConfig.LOGGER.warn("Async target finding is incompatible with Parallel World Ticking. Disabling Async target finding automatically."); enabled = false; } alertOther = config.getBoolean(getBasePath() + ".async-alert-other", true); searchBlock = config.getBoolean(getBasePath() + ".async-search-block", true); searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true); queueSize = config.getInt(getBasePath() + ".queue-size", 0); - threshold = config.getLong(getBasePath() + ".threshold", 0); if (queueSize <= 0) { queueSize = 4096; } - if (threshold == 0L) { - threshold = 10L; - } if (!enabled) { alertOther = false; searchEntity = false; From d38c7b74c9a0ebaba3b34f8f441827b826d40150 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Wed, 18 Jun 2025 00:03:28 +1400 Subject: [PATCH 05/26] Remove dead instance checks in AsyncLocator --- .../features/0178-Asynchronous-locator.patch | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch b/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch index 687248d6..7ec2a2dd 100644 --- a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch +++ b/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch @@ -7,43 +7,39 @@ Original license: MIT Original project: https://github.com/thebrightspark/AsyncLocator diff --git a/net/minecraft/server/commands/LocateCommand.java b/net/minecraft/server/commands/LocateCommand.java -index 2723d5377567241921fef61952e474c1c0ee9bbf..0918b528e0310b12378e185b29a478ed188a2d58 100644 +index 2723d5377567241921fef61952e474c1c0ee9bbf..548a33b857aef542279255368031a095037b76bb 100644 --- a/net/minecraft/server/commands/LocateCommand.java +++ b/net/minecraft/server/commands/LocateCommand.java -@@ -109,6 +109,38 @@ public class LocateCommand { +@@ -109,6 +109,34 @@ public class LocateCommand { BlockPos blockPos = BlockPos.containing(source.getPosition()); ServerLevel level = source.getLevel(); Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER); + // Leaf start - Asynchronous locator + if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled) { -+ net.minecraft.commands.CommandSource locatorSource = source.source; -+ if (locatorSource instanceof net.minecraft.server.level.ServerPlayer || locatorSource instanceof net.minecraft.server.MinecraftServer) { -+ BlockPos originPos = BlockPos.containing(source.getPosition()); ++ BlockPos originPos = BlockPos.containing(source.getPosition()); ++ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false) ++ .thenOnServerThread(pair -> { ++ stopwatch.stop(); ++ if (pair != null) { ++ showLocateResult( ++ source, ++ structure, ++ originPos, ++ pair, ++ "commands.locate.structure.success", ++ false, ++ stopwatch.elapsed() ++ ); ++ } else { ++ source.sendFailure( ++ Component.literal( ++ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage() ++ ) ++ ); ++ } ++ }); + -+ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false) -+ .thenOnServerThread(pair -> { -+ stopwatch.stop(); -+ if (pair != null) { -+ showLocateResult( -+ source, -+ structure, -+ originPos, -+ pair, -+ "commands.locate.structure.success", -+ false, -+ stopwatch.elapsed() -+ ); -+ } else { -+ source.sendFailure( -+ Component.literal( -+ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage() -+ ) -+ ); -+ } -+ }); -+ -+ return 0; -+ } ++ return 0; + } + // Leaf end - Asynchronous locator Pair> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false); From 3c9c28f5983e43c0801da8ebe095b80fb2a88554 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:30:48 +1400 Subject: [PATCH 06/26] Always poll ServerChunkCache tasks on main --- .../features/0178-Asynchronous-locator.patch | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch b/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch index 7ec2a2dd..07c84259 100644 --- a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch +++ b/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch @@ -45,6 +45,40 @@ index 2723d5377567241921fef61952e474c1c0ee9bbf..548a33b857aef542279255368031a095 Pair> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false); stopwatch.stop(); if (pair == null) { +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index 6d5a15122079f2d1568ceb7086db21ad454f58e6..ecab2befa1f2f993ea4b4d088529745c2a37b73d 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -848,14 +848,25 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + + @Override + public boolean pollTask() { ++ // Leaf start - Async Locator + // Paper start - rewrite chunk system +- final ServerChunkCache serverChunkCache = ServerChunkCache.this; +- if (serverChunkCache.runDistanceManagerUpdates()) { +- return true; ++ java.util.function.Supplier supplier = () -> { ++ final ServerChunkCache serverChunkCache = ServerChunkCache.this; ++ if (serverChunkCache.runDistanceManagerUpdates()) { ++ return true; ++ } else { ++ return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); ++ } ++ }; ++ if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled && Thread.currentThread() instanceof org.dreeam.leaf.async.locate.AsyncLocator.AsyncLocatorThread) { ++ return MinecraftServer.getServer().scheduleWithResult((java.util.concurrent.CompletableFuture future) -> { ++ future.complete(supplier.get()); ++ }).join(); + } else { +- return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); ++ return supplier.get(); + } + // Paper end - rewrite chunk system ++ // Leaf end - Async Locator + } + } + } diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java index 87ba416479df56bad5d13c01e96e92e45b7802a3..2508645b62e7f935dee00fe87b3a6446dbd22cf2 100644 --- a/net/minecraft/world/entity/animal/Dolphin.java From de2562294c1177847a2cdcfb9b090fbd32116f5f Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Wed, 18 Jun 2025 06:10:51 +1400 Subject: [PATCH 07/26] Backport AsyncLocator fixes --- .../features/0089-Asynchronous-locator.patch | 88 +++++++++++++------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0089-Asynchronous-locator.patch b/leaf-server/minecraft-patches/features/0089-Asynchronous-locator.patch index ee20df93..1f71b727 100644 --- a/leaf-server/minecraft-patches/features/0089-Asynchronous-locator.patch +++ b/leaf-server/minecraft-patches/features/0089-Asynchronous-locator.patch @@ -7,48 +7,78 @@ Original license: MIT Original project: https://github.com/thebrightspark/AsyncLocator diff --git a/net/minecraft/server/commands/LocateCommand.java b/net/minecraft/server/commands/LocateCommand.java -index 13bcd8653d766cd0b754a22e9aab261fbc62b0a5..e3e7c4e4da0bc95b015bb84e470477782bdb691c 100644 +index 13bcd8653d766cd0b754a22e9aab261fbc62b0a5..13542755864904b343b0aeea957e2a76e977a51f 100644 --- a/net/minecraft/server/commands/LocateCommand.java +++ b/net/minecraft/server/commands/LocateCommand.java -@@ -109,6 +109,38 @@ public class LocateCommand { +@@ -109,6 +109,34 @@ public class LocateCommand { BlockPos blockPos = BlockPos.containing(source.getPosition()); ServerLevel level = source.getLevel(); Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER); + // Leaf start - Asynchronous locator + if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled) { -+ net.minecraft.commands.CommandSource locatorSource = source.source; -+ if (locatorSource instanceof net.minecraft.server.level.ServerPlayer || locatorSource instanceof net.minecraft.server.MinecraftServer) { -+ BlockPos originPos = BlockPos.containing(source.getPosition()); ++ BlockPos originPos = BlockPos.containing(source.getPosition()); ++ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false) ++ .thenOnServerThread(pair -> { ++ stopwatch.stop(); ++ if (pair != null) { ++ showLocateResult( ++ source, ++ structure, ++ originPos, ++ pair, ++ "commands.locate.structure.success", ++ false, ++ stopwatch.elapsed() ++ ); ++ } else { ++ source.sendFailure( ++ Component.literal( ++ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage() ++ ) ++ ); ++ } ++ }); + -+ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false) -+ .thenOnServerThread(pair -> { -+ stopwatch.stop(); -+ if (pair != null) { -+ showLocateResult( -+ source, -+ structure, -+ originPos, -+ pair, -+ "commands.locate.structure.success", -+ false, -+ stopwatch.elapsed() -+ ); -+ } else { -+ source.sendFailure( -+ Component.literal( -+ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage() -+ ) -+ ); -+ } -+ }); -+ -+ return 0; -+ } ++ return 0; + } + // Leaf end - Asynchronous locator Pair> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false); stopwatch.stop(); if (pair == null) { +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index 0fd51020ca9480be2855eb58a7d4d43511829512..52a2b993bbd1ad4851b3273af6ecbc069beb5b84 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -878,14 +878,25 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + + @Override + public boolean pollTask() { ++ // Leaf start - Async Locator + // Paper start - rewrite chunk system +- final ServerChunkCache serverChunkCache = ServerChunkCache.this; +- if (serverChunkCache.runDistanceManagerUpdates()) { +- return true; ++ java.util.function.Supplier supplier = () -> { ++ final ServerChunkCache serverChunkCache = ServerChunkCache.this; ++ if (serverChunkCache.runDistanceManagerUpdates()) { ++ return true; ++ } else { ++ return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); ++ } ++ }; ++ if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled && Thread.currentThread() instanceof org.dreeam.leaf.async.locate.AsyncLocator.AsyncLocatorThread) { ++ return MinecraftServer.getServer().scheduleWithResult((java.util.concurrent.CompletableFuture future) -> { ++ future.complete(supplier.get()); ++ }).join(); + } else { +- return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); ++ return supplier.get(); + } + // Paper end - rewrite chunk system ++ // Leaf end - Async Locator + } + } + } diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java index 7003b532182737a745491e397a967b72e6b308aa..3ed9652510976770f5661dd7b317f27f046700d4 100644 --- a/net/minecraft/world/entity/animal/Dolphin.java From a87c3ecba3255b1cb4852742842bba30722cec7d Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:18:50 +0800 Subject: [PATCH 08/26] [ci skip] Add RainYun ad --- README.md | 12 ++++++++++-- public/image/RainYun.jpg | Bin 0 -> 11463 bytes public/readme/README_CN.md | 14 +++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 public/image/RainYun.jpg diff --git a/README.md b/README.md index 448e318a..e5030e43 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ If these excellent projects hadn't existed, Leaf wouldn't have become great. ## 🔥 Special Thanks -Jianke Cloud Host +[![Jianke Cloud Host](public/image/JiankeServer.jpg)](https://cloud.swordsman.com.cn/?i8ab42c) \ cloud of swordsman | 剑客云 If you want to find a cheaper, high performance, stable, lower latency host, then cloud of swordsman is a good choice! Registers and purchases in [here](https://cloud.swordsman.com.cn/?i8ab42c). @@ -131,7 +131,15 @@ If you want to find a cheaper, high performance, stable, lower latency host, the 如果你想找一个低价高性能、低延迟的云服务商,剑客云是个不错的选择!你可以在 [这里](https://cloud.swordsman.com.cn/?i8ab42c) 注册。 --- -![YourKit](https://www.yourkit.com/images/yklogo.png) +[![雨云](public/image/RainYun.jpg)](https://www.rainyun.com/NzE2NTc1_) \ +RainYun | 雨云 + +Global multi-line routing with cloud storage. Refund available within 7 days. Reliable uptime and expert support. RainYun — stable, cost-effective, and ready for fast cloud deployment. Visit [RainYun]([雨云](https://www.rainyun.com/NzE2NTc1_)) + +国际多线路选择,配套云存储 — 购买服务后七天内不满意可以申请退订,强大的技术支持团队和高在线率客服。雨云云服务器,用稳定和性价比,助力您快速上云。点击前往 [雨云](https://www.rainyun.com/NzE2NTc1_)。 + +--- +![YourKit](https://www.yourkit.com/images/yklogo.png) \ YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications. diff --git a/public/image/RainYun.jpg b/public/image/RainYun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38e45e58cc8a2684d092c9c56bcb1da04d91fd88 GIT binary patch literal 11463 zcmb7qby!s0_Wwa@2$5D&kWQr=6eNcnx}_UsKvF^lK{|$Rh8c3`21P`=8-|kZkdRXN z;eGG#-uM1-@AG`udCop-?e#fpt-a>V?Ahz=o9UbH0I`aKvI2mC0RR}c2XM2DF|8~o zXRZm+P*7Ht|4Y#g+!EFk0B~{jfI<{y84L`K7;wM;b;lo_g_ZlOKiB_4w|0L{{;>`K zV?6%_^S`?BtZm$_ZUKk4Co}Zc`E9V|w>-JsUp)IC-tsSA@(=Ij@yg>Cqxpx2>Okaf zdFxxA-R^I^<==R#SI|HB$Xkr0i}UM0zW&gkhzV_6b+vD=pxcuca0eiOA|U%`{I~Kg zz03mu(Nh4xjQw|?WhwyFhXB9>^uPOBCN@4U4(>l7|EK2W3qS$_-eN#8F&+VTNH8!-FmAp9^nV^F>_6fC|Iq^Y*f_W# zJSlQ)+!Xstm!zX*DWkF8;$iVGwT;ezd z6~C;uep2oz z04~O@X%OZeyj!&>$!+2=F>vnS-NC~B3v%lln*@qLJS0jQJ!ef(?+(v!tAR32J7WHnBpLHb> zWh#1^uhmP7ej+LLLf_=v04b3d(TPHk!=}P*iugpyI^o*n8mu9QrNvNW;n`iJ3w>yqa9YMEV;f{u zhbMs(UI&6sU=JguKXeny!CA{$Xn9pE zzX=*ggGVM!_m_7{C#aPt|IU?U6_}T zGO}?wygw7MGoTlD5zv8*v?A2V`}XHt(MFFI;Zh=U&;9uWsK zU@?L)K(c@=anS!sz+4lNVPO~v@O7!v%nq*CBgM_=xC4(kcK|c1nUPu-gxL(b|EB7! zHQh6T=#$S&uLoFYyGZ98NLQ)9abFyM*6&F|-XH8XIpRBLRzr<$k`gKtEKpZ}jPB_{ zW{Gxkie6T!j_lGWq1eZZ3ZZIjhxv`?Eva^NZdsF`c*c!|n`4^%P`oWi=$U6Kvh{># zKbYWoeC+cLU!r575i6iWTSV9~D_ndV;ovNa854Z&ngxSP&54!-4ZW3Q3W8j=IAnBjG~XnX0s=8Ln4;tzklMzzoV*gnKSZtQtyB&V$E~llhg~X9o zH-)tl14V2`+XBCsCCn*wWUDvKLXTqMqjszSj-F1T59Hy}#<9oqWB94#j1&tt0bVt$%;fX2H(Zdh=`Y}f|1fl;6s8{fmq^wP*@ zBk#d!+A-4;TU1+<=|s{W66TJNW=@JYG33QE>O&Z^8mjh9AM)LadxbC0npPayobOJC z0${{}G6LU8My03@!!}$#nG1)1TPm#VTeKg@uh(Ovys)t;pg+_{1kg1J$(7}Gt6was2!ok)EOMd>Vd-=+& zy=X$cEZM(Tt!_aCdc|wwNsL90EBd_3$&xr22xbHrK~F)l#CQHrg5@65llJ|0ac6dl z$#gT17EkkYCFZR?_LsH0da^Ym@mgH@8XfT<~7X_Q?@W{Op*?3u`P1^G)lEk=pq)9)E z<4zxosAA^~lc!Ile^4$we7wvnSKWDIYM_L@wzj)0|B3H}O_qDZ1eCos_E4;i_w!5X zxrkJs6@l&foZQ^$^bmB~4Ir*7A~2!A7XjW8zE&ENx=V8d{DXCw#k)E;Yf z^$!!2?KB*u$3ypQc9%KY~w+~l>{3+pl}`(GUwTJcXyO#Ak`XxR_rIPt*j zLxqu3H^77Kh_MIdxK8zVHme4+R^!YDyCsq~I`z|ojy%65R$tzS53}*QudL190Ad+* zTiK3Vd(zY61qxg4@5|V;xZSepy-jSX+?{jxxfYVdQRa<~y z;Aud3^p9(;WYpEWRCma12_&1q#mZX(_I@;x=sn$*%@Or zdcB?p3|-fy&Q?SWFmhL{!qxivZPEk=wC}dS(Rtzwc%)w+l^patDgHozx&i!O?#eBu zOvbF#`dwcxP6x5*g2KyN`A`qL9M68AwpQK?uriW~o;bML3A6+fbslkk{?%C%NLR9W zHhKL`>LSYiT0+0|0QEcUj;>}{@zpW)$S=?Gz(wOL;`J0680R~8swNVuf-D1h> z@B;1rruk9UY}>EP!bO&d7%m{-OqbQ={2)7M{8d9DdFKIUX+;>~>X3R!(wh%=%JEwB z?7L8w_o3yzvWZ_gct*01k`KN(N&fi$?V)MOh1_D$q|ZuQ7=5$;Q4os*DBQdiqx87z zJ+Z%M`P#hzOv8;B9EQt1^Ijk^{}D&PFP!QjdctR?=vJ82`CYp#$p`OuY6IEt=*9kr zORdz`-cGcW`uRke2FmXz=K0EdqxkCs$7o8sr3|&?jzB4L2}+uM-rS7CFYwsD5(n}9 zl(Bp{XWF{Y!fM3{yHwGHpmyuOlviY74*D{g;z6QEqpdS~cES-GuXOh#vY;qq&ixQc z2y*DEg2@tW~$c8v$;%?jZ6{?vv`NvQHmu1Fzr-nxzO6YBW=!=skN%hzh~l>06S zx9McsHG~(0KDMx18flBLC8^5irVZOWI%IldXG(hNXQ>d!5>dCJ4WlsyQw@nPE+K;? z+Sw%)w=x$DHhCHBSKyto)sXv$C7W*DYzt*$3Y;WJ0ck>t?D#w3u}O;6h^*aad(oG2 zj(SFFHLx5JmPcRk0F35W=Nz<5RVNZch(vQ2j-t^wR-psZYPDm1snvV;OIgMYtv{sA z%S}6)<0p7K%KRvpxB*DdeYih!O(^D#R&0Mu&e3|n5uXQ%{|0x|vlbrnVI~`eDlI;s zI-5`RcYj=3KnHKF57ohkH`6mcwZdePE+QTDyH{hSDPdp(6WkI1eQD zj_B~k-GpEZE`3VglGm$wmM+>=bL8K?Rx<>IH^dz6Mz*?|==9~m=FMPR+D>zj-1t~U z;@sgE_dFOufVW%N4X}mT(=uruetzs{nLyUyz0GS}htLHVH!fn!+B$SqGxXWs3mqc` zqNR4o*BDl=KZ@I%`-)od5*kc2(ZRKB<-;?r)z9S0y#&B-9;f?o9GYo|Q4xWNaf-dl z(F4-@MAxuSyTb?OwP|n4=zeqf&A=JXW_+!^>z0!9;CoLFs!qCpxU@f(S46)c^j~Oo z61*^xxP+WlE3|HH6c?z_nbd%NoAY%BDhEu-UiOU|=ju-J*A~GL>J-?5kwF9szXnf1 zbM#k_RbwdU_)m2FkwS8YNp;*#lkfR#8zYkL*1xQ`dGtm*rT%$mU#D~5akzVyn_ri^ zFpifw%BoaT!7z5QbBc-SYWjJlC>qy4J$=rv{fozb{Q_t zK(xLSdV&P`p;C=`PgUuQamGA!s_S{zOOl*Vihx+6}v^Rrqb zvAq@X*iTU6ZyAYu!vNa+TU!490OiRa{-;ZY9!J<2kluVzjh(mI zQ(iHT23fweE1s+^x_Q^EOx<6vB0p~>lfU-;Byy?C z@{o0Edg_hom!yh?@QF6HatRUMf_C-#C!?~%O3bulu}p5X;>}ic`D6`5DKq^($l`*K zT0ustB3SOQjINx(=AclTwuMF=y)>Qyy01j)M_WJz4V&}Kd_yjQ|AP^@QHI$rBvJ>K zVH4coY5l44j836xg3U-B5}DSw5y={b_}WD3;w*vGUU=%_0NXG}OOm$|ZmbSH7PJHp zt_Ey1AUVs#YlRW8K7=_%#T$}jMRQonz!Y`3i{bJN!$({drOiV^r&X_kYI)gN7kGY7 zCH|{O$YHp$e^{WFk#G1>i8R!uHT`x0dj8`-)|@0hFHpUEoSSM?QyT6=cQWI>aDf4~ zp(L|_?rO_i2UO>NI24U*uOXCVUdC`YI2af7^kFyybHWG-_88~69_yA*xOaF##JlFO z+QyU8?C{;=J}OV^To_n`<_CTH`vxAbUh(7?G=yVOL@*tq8+6aW*?v zN3!UlL2 zqmml|*qVb=8H*Uo&?%Uhu{}J)nE_*$)=>-wz@9#!#=Q+#z!;Omteq)czbw=M9jAz@+yYt4r3(!6lCXmE)nlHSwOBVpp4BgxCtZVYgL$Eg>R z>1m1G!(nGoH~!laCA}fSq>5BQovq)GlVF#{fJ8sd2>MQ_ZRIZ}+yEUoMJY^{_4kF+ z)ViQQ8M6?6(Mr@Q)_`%^lZ-!=BF3rl|NB_ZQ5b^DDk_P2l*~amN6wA&id++{t2-UMF}q_Y=15!gTwEl42cEU@z@wdQqU-^w7nl-1OJUMeuL`w zdZ#5%EB5YrBDZxMib9h##FDy(Vt9A&4$~3^P1ACE3vVxCR#SQ951 zX>`Hij5ZXJT%xYC9ij5!IRgEDsn%y!7PR|FgnGNtLC>Zf(!y1K3=u5CEnuUa|1LO+ zKj{@K!otee`L5y3B>AR(aKo$d3I`o$(Y)Tzu^H8``PJORr4W89Qu!SvC}UD}GRMWv z=8?vCV@2&vFj#d?tmerqt5z*xlkB20T^=yr-di>?pCw07=`>D$@G@rbvROZHz?0|l zUFO~o`d=|x9~29}kdhpf)O!7zvRo|WSXdGVTr(!V`JseO{{9HD%cx)OGkW=9IMq+!<^ac=`uHVM@s{iI!C8h8W zjNCslW`8gNfA<)6X6+lv&lDEK?5@7XYOk$RP^q2JR%)m%K!})3+@}-q)xp5M3e*a= zj3POeBa|IcBz$=h?!?%;PCw#EKqNk``BZOrP>-FgCNJX( zsnuDvgI0dnDI^`|JXMm|`pW*K9?9As!UALSg^H1u4`AkJR7HL2lji$jnW>TJGm~n_ zn(lULdo=5OXK6=^RwL=rkWxT6iaxFuEq;j}eV4PANNeksM9+T%s8er*4y4~ruzyXd zqHCef(YQjjITfniBac+8cj|+1fx$6IWgb-&EjcPEkt93oiF`nmz)L+_`|78AeNEb_ zR4zmzKAnm~G$ct{4$HPQLcV>hzFEsuMNcx5Ow9a<*rLB4UB-}PYccekI4FcX7>i-g zZ}{;>(l-UKXHZ?EC}ioO(OihabYP>a1Fkit4kUp;BewdI>zwnLKIL5S_%S@gVjLxt z5n{_Ud?8c#x4Onfzq*P_pkta#OQ%(a0Zq#x?kKM_Q;wKv%d|%wn4c}%$B_2zL%Lsa>{O%aT@tbQ@%it!Vn0_!I-ROYdtWCgs_`q!caeJ{ZT0xI zOZuWsF>{FCZZP9_-4;`DDxESvsf83T(r`I=z34Y|9jhL?o?d|l`?SyaEOU`C5oxb; ze+orc>szaofBjruY|65FM_}D(!>+gf1iPn3#G}x|j$|l^UpVyKwbXL7i?AY>hXT3M zT0}ktY|4#A30JS;X|Yu(%pWEHAo2QKqf*;Mi*_8TE+Y2?B;pC2GBh#a?ddvJ19F}c zUhB0jEb;!)ZcYB`(ER+kFMZwp;tA^z$eWSzc?mHwK~uq#qGrMLj8WGB*xm$xUmwyh zIs~boZc!&oibAchwrwuIAQE#d`?~QX#$cVmAhLRp(K|#vEA6G7RFRL!^Og1+059a? z(e{*!um6G*q%*wR%NcCSQGl6Ew3=kA|CrD2vEb_={Vuk=fnhEcPI}m}uiU`YLLH(& zA}MW;fH7kSGsmH8#{X*VWpFlyK}5?iNn}$ zLgux0%78AeChf71pR#3HFjiJk?sq3Yjk>U_@nayOlJ_Iv4liR}_HX=f!tA19BD5v$ zoCX~dG55dA5ctuOov$h_i#vE3r+Sw(mm{E=TI*DB5{eq>MzJnNReo*_wC$UAZY;DC-~ zKNutO^U(l_q+zK!oOIFhp^t4?7Wd@ik&iDcse}cqO|xq770L!^G71bS#Jt?Zj~#lz z;?G_b_S7f!P230ONQW61$d<(OT{%>aFf(ZL_BaKt;AT9VLV2Ibj09(jX-94ONSEQ7 zXp2?Vw>9%Z^~A9tB}Uh{?2wAcHt#l_U|7BsF`->K>2s*Ll)x;h455PKO;VZ|CX` zQ+%^tub^D&z>?%=CbE-c`KL4(yES5uH8{zV)$G~YklL}igH7)9b?zWpU%i?W+vkOc za@dE*ijizN-^(a8sgcG%*Tfn*o#9sRi22c4=Y3iODq0H&_Jo!%l+(lI&z}I)0tU08 zXO_mhifOrd!XdDCZ*@lw?y>mvUwq!IUn8karma>Q3Oni4kCuhjKN+DQe9-pG@_7Y* zzR4-4L^;;MBUjV<_;_FFJ`1sghGCGn*jc$f*D>RV0A&0X-^D+LtUm%t!&B0q3L%#a z4M8iuf(GF#A1q{N5*cC+6}LTjM<_V))gvc)U#!b)wv~dj>SKkr= z?POJF58(im+Wk6MCAST?|E~cF?b>nnx!-8wg>Y}^kU7!0K=O%QsLY(WNQu!E-!GX^ zZyU~DB&%~8lS__mZCTbZ;2ED%wh`~n7vfexY|>D?{uZ1f)y|$rsfikF9QAwpUGhgn zy*;Oi5dEO!ef=4#zK+Q#xbhydY7wisnn}BK_faVe7-2N|t6RB8{v)eya*krjr9gZ3 zJ{`>j%0H#;+}}7W*Yt>tpI2;YfU%zD*)K~SC`VsGq_Y+yL%g>lYI63P&QKoAQHK2~ z{HR>qN3H91$I?%Bfd@VxAW`?%OVgO_l?K43QaQjLvtnd0n$_pde5*k)5z= zOX8TW(qF@_xKC~m!40PBlwRkpo6-y!amc;9X-8zZ(-#^#H;_G&MSBCh+FU?6?RK5a zXTQ)QE~?w}RV~)^jL1{2!CD*3GR~_&I5QV1GKh8(brL>L>b)sUY`v zBHB&9F@id&s$=HLB>EaE3b0?DNL{EbmFnnBOZugLw0(O6%x5b{(<^FR=outPxH-() zEmg6~=A%l5lf8v55(KmpR9;=oI+~Bn(tZgNH|%k(VA(P9ojZp^ti+532se*g3| zNR}D(>qxW!%@tGDd6&pXOaI+m$_`cRXPaG}PJKr*wF7K>hn~7&qJ3<^ z^&|;?skng$TY3#?k%RP(y~72HsjM(GU4?nWHss=Ar^I7cWMZIg3%?6!Uvn{0o(>Ns_Nad(s=(ZKhGHq{tq1RmoIO789e%92g@z zb72+$+S=go^!LPeQgk6p*Z*E|hNoG}!fZ|FUCUWUC#D_m+rl&d1otsKrzJImO*8_9 zlkC~BFy<+hsfXf{rUAQ<;vHpdxMQBUZ$|qon)xsb+j*{-@hwx?$++|Q+K7rJ6K$pX z%(eXPmLkT5E`gp>;=sg}Ej+^-NZhvYB875U@e zx2YsLV}7b8+GEv9m)CIyDB|XfqU3Ul;T(d?XqD)0q$MDgRNxLh$#VvBF8LlsDw>!z9nvD0+Se&f6q_uO)#&FAd>=#- zXWX@?*PV-uu!0lfVW-^0yL}%lEo$9oh+)nJ%!vWGxkR^Tc~i zru0YkZ1%?*QqX=i8Q!^ePWy&qE=OwXbztbXf`vlf>QI-# z3kIfbFYa?!K{Hd(2f6q4@^6t?pgm81uNgarD$;g90JN^~N9T*BQ-BG^ENyANc~mt3~gbRq^)xtV)bCKYf)SAhg>M{q4t4IWL?t zG2K~XVd9&X1E!O=z&(sKLj}L_^6%mrS;F)mJ*kqNS@5=`3Q7}Nvf{0H z0vkIMAA9AWe-0q1AKHB(tlq;p@%!jD|JNC({=bqJyQ?d|UP0&K$hYc-s^dpQqiyGR zUrD>Sk3BH&qk5=>R$USDk%&?&X;iJSa9#VJYoYRIRFenH20ugUWqhY-av>l{;-|Bx z1Ke<_ZT&+!HV?m<0{AF;LTzoq%)b@8Ze+A!=O8+I=MBuys&(y}pdORkM&C*1wZPu( z)Kbuxz;FY!_{HQ(#K5BARPbOQb{#_k-`Ebyl*x9|yYkli z-qJ=7(>O-7OAX4GeK=Iw<;*{@ASjq|HG+v*K^rC(#y_=RC#h&F>n!#7Suz5WW+3q{ ztpHp!{?oZ-rAR8LGeOb+Bzd)S+DOp>&(~^C8%+JHbYR0>ebOAJOOlLLg{0R;=3oj@LS9VkB;>bz_|@z1UWZ1%xr_j`@g>N%5jWuFnzv=bK#aProHpr%NcHORYr zZ^)6(o!{Q&D}IgrgI>=@vX< z{42*q(g^Z`SKW}|Df0+^>+hW; zjm3H9T!Tl)sj67U!h|x{eT{2GS7~P~LL{KeBkY2=)q|XkjdM9s=Q$CKoTOBc$EdDS z?Bx`!|HRxbLvwjB@-tu#If(M#E-)Npt zOzm5!nxmTP6}#zN;`B=EDc0$O?OzzKy%t1dN~(EKMS{IaGY4a}rU8=RBHU8q$hNS3 zX!6SwGwLy?pR+Hq3G~L{W8|^QGmy1!OP9zlP&~Iglj@*aM;wweVd_Kt!~lmAY^J#h z$wpUz4Db7x)KepzG@6&A0)a6To~<%~E)@NJ*dLg3z1*}3v_#L$q&K<|cJJ97uC3-z z^BnxnA6w?mI!Pe>^>U|GapuZxgvZo~2z}XdVpU*2@3h42+i)^)nYRVs=AE#Uci^ec^QZWo9VL1- zM7B0-I0!_*9_gLj7D{XF2N0x252mT$@1u=Nc>TS0o6U> zetqUwR=7pcxDE|kF5n^=Y}MhlQN@f$Kqy(i6!(&?MWS$J2Z1t{Ph=n;Bg$ef(}_lH zkJZsv!PtAfL`*l8L$AQT>I6%4_;phJlz1X`!4eBczs)!LhPL^wyAoYgHvpXJ+8QG- zEws`!l6evy@|tR9-_ocNl9DT_azvoBS{*6)ek#4!9%Cw5M}=DK-ut;E*2820eWzI7WskeZ9#-+WzBu@8ptuuA29m!I$!=(21j*ma{nzF?jAhA+ Y|J-l)C`gt#{O!L0|K5rxb2Ib*0H3lJmH+?% literal 0 HcmV?d00001 diff --git a/public/readme/README_CN.md b/public/readme/README_CN.md index 1ecc4200..90bc1789 100644 --- a/public/readme/README_CN.md +++ b/public/readme/README_CN.md @@ -123,15 +123,23 @@ Leaf 根据其上游项目及其他材料,采用多种开源许可证授权, ## 🔥 特别感谢 -Jianke Cloud Host -剑客云 | cloud of swordsman +[![Jianke Cloud Host](../image/JiankeServer.jpg)](https://cloud.swordsman.com.cn/?i8ab42c) \ +cloud of swordsman | 剑客云 如果你想找一个低价高性能、低延迟的云服务商,剑客云是个不错的选择!你可以在 [这里](https://cloud.swordsman.com.cn/?i8ab42c) 注册。 If you want to find a cheaper, high performance, stable, lower latency host, then cloud of swordsman is a good choice! Registers and purchases in [here](https://cloud.swordsman.com.cn/?i8ab42c). --- -![YourKit](https://www.yourkit.com/images/yklogo.png) +[![雨云](../image/RainYun.jpg)](https://www.rainyun.com/NzE2NTc1_) \ +雨云 + +国际多线路选择,配套云存储 — 购买服务后七天内不满意可以申请退订,强大的技术支持团队和高在线率客服。雨云云服务器,用稳定和性价比,助力您快速上云。点击前往 [雨云](https://www.rainyun.com/NzE2NTc1_)。 + +Global multi-line routing with cloud storage. Refund available within 7 days. Reliable uptime and expert support. RainYun — stable, cost-effective, and ready for fast cloud deployment. Visit [RainYun]([雨云](https://www.rainyun.com/NzE2NTc1_)) + +--- +![YourKit](https://www.yourkit.com/images/yklogo.png) \ YourKit 通过创新和智能的工具支持开源项目,用于监控和分析 Java 和 .NET 应用程序。 YourKit 是 [YourKit Java Profiler](https://www.yourkit.com/java/profiler/)、 From 6d86da82c146743eceb3e8d528557a40b034601a Mon Sep 17 00:00:00 2001 From: Taiyou <77050201+Taiyou06@users.noreply.github.com> Date: Wed, 18 Jun 2025 06:56:23 +0200 Subject: [PATCH 09/26] Optimize random tick (#359) * optimize random tick * rebase * fix random tick chance check * add back zero check fix always tick on first tick * optimize random check * cleanup * remove 0 to 2 random on amount chosen * cleanup * add queue and reuse block count * reduce LevelChunkSection#tickingBlocks memory overhead * Revert "reduce LevelChunkSection#tickingBlocks memory overhead" This reverts commit 942376481bf775324ce6349766200b5f044bffa0. * fix overflow * [ci skip] rebuild patches --------- Co-authored-by: hayanesuru --- .../features/0192-optimize-random-tick.patch | 105 +++++++++++ .../modules/opt/OptimizeRandomTick.java | 20 +++ .../dreeam/leaf/world/RandomTickSystem.java | 164 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 leaf-server/minecraft-patches/features/0192-optimize-random-tick.patch create mode 100644 leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java create mode 100644 leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java diff --git a/leaf-server/minecraft-patches/features/0192-optimize-random-tick.patch b/leaf-server/minecraft-patches/features/0192-optimize-random-tick.patch new file mode 100644 index 00000000..76b1f5a9 --- /dev/null +++ b/leaf-server/minecraft-patches/features/0192-optimize-random-tick.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hayanesuru +Date: Fri, 6 Jun 2025 20:46:10 +0900 +Subject: [PATCH] optimize random tick + + +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index c80e6669013d3cf87b51d0cb0b62fcf5466d702c..9d132c88629976cc00d470980308571ac3222284 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -693,6 +693,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + this.level.tickChunk(levelChunk, _int); + } + } ++ this.level.randomTickSystem.tick(this.level); // Leaf - optimize random tick + + if (flagAndHasNaturalSpawn) { // Gale - MultiPaper - skip unnecessary mob spawning computations + this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index 7cbcc2dd8533973108841d3989265a392a6f6214..bc0c80ed78bbb594cf7281e8d87f27dd06a1fcbb 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -1120,6 +1120,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking + ++ public org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting + ChunkPos pos = chunk.getPos(); +@@ -1169,7 +1170,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } // Paper - Option to disable ice and snow + + if (randomTickSpeed > 0) { +- this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking ++ if (org.dreeam.leaf.config.modules.opt.OptimizeRandomTick.enabled) randomTickSystem.tickChunk(this.simpleRandom, chunk, randomTickSpeed); // Leaf - random tick ++ else this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking // Leaf - random tick + } + } + +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index a90bf0d80ae4dac9b19b8e467b402917cc19a271..44b672671e0bea6a5f91e9b8573f9a8225a20f6a 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -149,6 +149,48 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + } + // Gale end - Airplane - optimize random calls in chunk ticking - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively + ++ // Leaf start - optimize random tick ++ private boolean leaf$tickingBlocksDirty = true; ++ private int leaf$tickingBlocksCount; ++ private int leaf$firstTickingSectionIndex = -1; ++ public final int leaf$tickingBlocksCount() { ++ if (!leaf$tickingBlocksDirty) { ++ return leaf$tickingBlocksCount; ++ } ++ leaf$tickingBlocksDirty = false; ++ int sum = 0; ++ leaf$firstTickingSectionIndex = -1; ++ for (int i = 0; i < sections.length; i++) { ++ LevelChunkSection section = sections[i]; ++ int size = section.moonrise$getTickingBlockList().size(); ++ if (size != 0 && leaf$firstTickingSectionIndex == -1) { ++ leaf$firstTickingSectionIndex = i; ++ } ++ sum += size; ++ } ++ leaf$tickingBlocksCount = sum; ++ return sum; ++ } ++ public final java.util.OptionalLong leaf$getTickingPos(int idx) { ++ if (leaf$firstTickingSectionIndex != -1) { ++ for (int i = leaf$firstTickingSectionIndex; i < sections.length; i++) { ++ LevelChunkSection section = sections[i]; ++ var l = section.moonrise$getTickingBlockList(); ++ int size = l.size(); ++ if (idx < size) { ++ short loc = l.getRaw(idx); ++ int x = (loc & 15) | (chunkPos.x << 4); ++ int y = (loc >>> 8) | ((getMinSectionY() + i) << 4); ++ int z = ((loc >>> 4) & 15) | (chunkPos.z << 4); ++ return java.util.OptionalLong.of(BlockPos.asLong(x, y, z)); ++ } ++ idx -= size; ++ } ++ } ++ leaf$tickingBlocksDirty = true; ++ return java.util.OptionalLong.empty(); ++ } ++ // Leaf end - optimize random tick + public LevelChunk(Level level, ChunkPos pos) { + this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); + } +@@ -417,6 +459,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + if (blockState == state) { + return null; + } else { ++ // Leaf start - optimize random tick ++ if (blockState.isRandomlyTicking() != state.isRandomlyTicking()) { ++ leaf$tickingBlocksDirty = true; ++ } ++ // Leaf end - optimize random tick + Block block = state.getBlock(); + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state); + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state); diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java new file mode 100644 index 00000000..525bcac7 --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java @@ -0,0 +1,20 @@ +package org.dreeam.leaf.config.modules.opt; + +import org.dreeam.leaf.config.ConfigModules; +import org.dreeam.leaf.config.EnumConfigCategory; +import org.dreeam.leaf.config.annotations.Experimental; + +public class OptimizeRandomTick extends ConfigModules { + + public String getBasePath() { + return EnumConfigCategory.PERF.getBaseKeyName() + ".optimise-random-tick"; + } + + @Experimental + public static boolean enabled = false; + + @Override + public void onLoaded() { + enabled = config.getBoolean(getBasePath(), enabled); + } +} diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java new file mode 100644 index 00000000..fdcaad27 --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java @@ -0,0 +1,164 @@ +package org.dreeam.leaf.world; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.material.FluidState; + +import java.util.OptionalLong; + +public final class RandomTickSystem { + private static final long SCALE = 0x100000L; + private static final long CHUNK_BLOCKS = 4096L; + + /// reduce unnecessary sampling and block counting + private static final long TICK_MASK = 0b11L; + private static final long TICK_MUL = 4L; + private static final int BITS_STEP = 2; + private static final int BITS_MAX = 60; + + private final LongArrayList queue = new LongArrayList(); + private final LongArrayList samples = new LongArrayList(); + private final LongArrayList weights = new LongArrayList(); + private long weightsSum = 0L; + + private int bits = 60; + private long cacheRandom = 0L; + + public void tick(ServerLevel world) { + if (weights.isEmpty() || samples.isEmpty()) { + return; + } + + final var random = world.simpleRandom; + final long chosen; + if (((weightsSum % SCALE) >= boundedNextLong(random, SCALE))) { + chosen = weightsSum / SCALE + 1L; + } else { + chosen = weightsSum / SCALE; + } + if (chosen == 0L) { + return; + } + + final long spoke = weightsSum / chosen; + if (spoke == 0L) { + return; + } + + final long[] weightsRaw = weights.elements(); + final long[] samplesRaw = samples.elements(); + + long accumulated = weightsRaw[0]; + long current = boundedNextLong(random, spoke); + int i = 0; + while (current < weightsSum) { + while (accumulated < current) { + i += 1; + accumulated += weightsRaw[i]; + } + queue.add(samplesRaw[i]); + current += spoke; + } + while (queue.size() < chosen) { + queue.add(samplesRaw[i]); + } + + long[] queueRaw = queue.elements(); + int j = 0; + int k; + for (k = queue.size() - 3; j < k; j += 4) { + final long packed1 = queueRaw[j]; + final long packed2 = queueRaw[j + 1]; + final long packed3 = queueRaw[j + 2]; + final long packed4 = queueRaw[j + 3]; + final LevelChunk chunk1 = getChunk(world, packed1); + final LevelChunk chunk2 = packed1 != packed2 ? getChunk(world, packed2) : chunk1; + final LevelChunk chunk3 = packed2 != packed3 ? getChunk(world, packed3) : chunk2; + final LevelChunk chunk4 = packed3 != packed4 ? getChunk(world, packed4) : chunk3; + if (chunk1 != null) tickBlock(world, chunk1, random); + if (chunk2 != null) tickBlock(world, chunk2, random); + if (chunk3 != null) tickBlock(world, chunk3, random); + if (chunk4 != null) tickBlock(world, chunk4, random); + } + for (k = queue.size(); j < k; j++) { + LevelChunk chunk = getChunk(world, queueRaw[j]); + if (chunk != null) tickBlock(world, chunk, random); + } + + weightsSum = 0L; + queue.clear(); + weights.clear(); + samples.clear(); + } + + private static LevelChunk getChunk(ServerLevel world, long packed) { + return world.chunkSource.getChunkAtIfLoadedImmediately((int) packed, (int) (packed >> 32)); + } + + private static void tickBlock(ServerLevel world, LevelChunk chunk, RandomSource random) { + OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(chunk.leaf$tickingBlocksCount())); + if (optionalPos.isEmpty()) { + return; + } + BlockPos pos = BlockPos.of(optionalPos.getAsLong()); + BlockState state = chunk.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); + state.randomTick(world, pos, random); + + final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294(); + if (doubleTickFluids) { + final FluidState fluidState = state.getFluidState(); + if (fluidState.isRandomlyTicking()) { + fluidState.randomTick(world, pos, random); + } + } + } + + public void tickChunk( + RandomSource random, + LevelChunk chunk, + long tickSpeed + ) { + if (this.bits == BITS_MAX) { + this.bits = 0; + this.cacheRandom = random.nextLong(); + } else { + this.bits += BITS_STEP; + } + if ((this.cacheRandom & (TICK_MASK << bits)) == 0L) { + long count = chunk.leaf$tickingBlocksCount(); + if (count != 0L) { + long weight = (TICK_MUL * tickSpeed * count * SCALE) / CHUNK_BLOCKS; + samples.add(chunk.getPos().longKey); + weights.add(weight); + weightsSum += weight; + } + } + } + + /** + * @param rng a random number generator to be used as a + * source of pseudorandom {@code long} values + * @param bound the upper bound (exclusive); must be greater than zero + * + * @return a pseudorandomly chosen {@code long} value + * + * @see java.util.random.RandomGenerator#nextLong(long) nextLong(bound) + */ + public static long boundedNextLong(RandomSource rng, long bound) { + final long m = bound - 1; + long r = rng.nextLong(); + if ((bound & m) == 0L) { + r &= m; + } else { + for (long u = r >>> 1; + u + m - (r = u % bound) < 0L; + u = rng.nextLong() >>> 1) + ; + } + return r; + } +} From adb6a645f6c8f718bb1c43b4df015c30fcbf85aa Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Mon, 16 Jun 2025 20:28:09 +0900 Subject: [PATCH 10/26] cleanup & remove threshold in async target finding --- .../features/0238-Async-target-finding.patch | 415 +++++++----------- .../features/0280-Paw-optimization.patch | 8 +- .../leaf/async/ai/AsyncGoalExecutor.java | 75 +--- .../dreeam/leaf/async/ai/AsyncGoalThread.java | 19 +- .../modules/async/AsyncTargetFinding.java | 7 +- 5 files changed, 193 insertions(+), 331 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch index 9ef1594f..78f696e6 100644 --- a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch +++ b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch @@ -134,7 +134,7 @@ index 72e871b8c7fee9b5cbd567e03baee80ee4b9c82e..574765713c194a6cf3eb7c125e78ed77 // Gale start - Pufferfish - SIMD support diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 4948557d2faef1dff664cd18df7af4564a0431ff..c0044f4013520fd617ec365012b10862571744f3 100644 +index 4948557d2faef1dff664cd18df7af4564a0431ff..224a032e8992f104ad9380182ed67c316c93274e 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -173,7 +173,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -163,26 +163,13 @@ index 4948557d2faef1dff664cd18df7af4564a0431ff..c0044f4013520fd617ec365012b10862 @Override public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { -@@ -334,6 +344,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); - } - -+ // Leaf start - Async target finding -+ public final void leafMidTickTasks() { -+ if (this.asyncGoalExecutor != null) this.asyncGoalExecutor.midTick(); -+ } -+ // Leaf end - Async target finding -+ - @Override - public final ChunkAccess moonrise$syncLoadNonFull(final int chunkX, final int chunkZ, final net.minecraft.world.level.chunk.status.ChunkStatus status) { - return this.moonrise$getChunkTaskScheduler().syncLoadNonFull(chunkX, chunkZ, status); -@@ -703,6 +719,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -703,6 +713,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle this.realPlayers = Lists.newArrayList(); // Leaves - skip this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.dreeam.leaf.async.world.SparklyPaperServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking + // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ this.asyncGoalExecutor = new org.dreeam.leaf.async.ai.AsyncGoalExecutor(server.asyncGoalThread, this); ++ this.asyncGoalExecutor = new org.dreeam.leaf.async.ai.AsyncGoalExecutor(this); + } else { + this.asyncGoalExecutor = null; + } @@ -190,39 +177,8 @@ index 4948557d2faef1dff664cd18df7af4564a0431ff..c0044f4013520fd617ec365012b10862 } // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads -@@ -976,12 +999,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - this.moonrise$midTickTasks(); // Paper - rewrite chunk system - // Gale end - Airplane - remove lambda from ticking guard - copied from guardEntityTick -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - } - } - } - ); - this.tickBlockEntities(); -+ if (this.asyncGoalExecutor != null) this.asyncGoalExecutor.tick(); // Leaf - Async target finding - } - // Paper - rewrite chunk system - } -@@ -1460,6 +1485,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - // Paper end - rewrite chunk system - -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - - private void tickBlock(BlockPos pos, Block block) { -@@ -1476,6 +1502,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - // Paper end - rewrite chunk system - -+ this.leafMidTickTasks(); // Leaf - Async target finding - } - - // Paper start - log detailed entity tick information diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java -index 81bd431e641be474f7a43a78df083756de1798de..7092599cfbce0c632775f70fc599172b51d9e2cd 100644 +index 81bd431e641be474f7a43a78df083756de1798de..5b56a0b81c822ff1c96e31992f305403fab7fc35 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java @@ -135,6 +135,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @@ -238,68 +194,39 @@ index 81bd431e641be474f7a43a78df083756de1798de..7092599cfbce0c632775f70fc599172b protected Mob(EntityType entityType, Level level) { super(entityType, level); -@@ -213,12 +219,22 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - } - // Paper end - Skip AI during inactive ticks for non-aware mobs - boolean isThrottled = org.dreeam.leaf.config.modules.opt.ThrottleInactiveGoalSelectorTick.enabled && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking -+ // Leaf start - Async target finding -+ boolean running = this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1; -+ this.tickingTarget = false; - if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking - this.goalSelector.tick(); - } -+ this.tickingTarget = true; +@@ -219,6 +225,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority this.targetSelector.tick(); } ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (!running && (this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1)) { -+ ((ServerLevel) this.level()).asyncGoalExecutor.submit(this.getId()); -+ } ++ ((ServerLevel) this.level()).asyncGoalExecutor.tickMob(this); + } + // Leaf end - Async target finding } // Paper end -@@ -765,17 +781,29 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - // Paper end - Allow nerfed mobs to jump and float - this.sensing.tick(); - int i = this.tickCount + this.getId(); -+ // Leaf start - Async target finding -+ boolean running = this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1; - if (i % 2 != 0 && this.tickCount > 1) { -+ this.tickingTarget = true; - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tickRunningGoals(false); -+ this.tickingTarget = false; - if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.goalSelector.tickRunningGoals(false); - } else { -+ this.tickingTarget = true; - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tick(); -+ this.tickingTarget = false; +@@ -776,6 +787,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.goalSelector.tick(); } ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (!running && (this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1)) { -+ ((ServerLevel) this.level()).asyncGoalExecutor.submit(this.getId()); -+ } ++ ((ServerLevel) this.level()).asyncGoalExecutor.tickMob(this); + } + // Leaf end - Async target finding this.navigation.tick(); this.customServerAiStep((ServerLevel)this.level()); diff --git a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java -index 7651676e72fcec52d7c1f9f7d7b6f9e585015c4d..ed3c5ad51ec0b9a1997e732e11db99ce06db7307 100644 +index 7651676e72fcec52d7c1f9f7d7b6f9e585015c4d..7b668d3bc679239668642a6d1d124bab67a26000 100644 --- a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java +++ b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java @@ -67,15 +67,24 @@ public class AvoidEntityGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async Avoid Entity Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (!poll()) { + getNearestEntityAsync(); @@ -313,11 +240,11 @@ index 7651676e72fcec52d7c1f9f7d7b6f9e585015c4d..ed3c5ad51ec0b9a1997e732e11db99ce this.mob, this.mob.getX(), - this.mob.getY(), -+ this.mob.getEyeY(), // Leaf - Async Avoid Entity Finding ++ this.mob.getEyeY(), // Leaf - Async target finding this.mob.getZ() ); + } -+ // Leaf end - Async Avoid Entity Finding ++ // Leaf end - Async target finding if (this.toAvoid == null) { return false; } else { @@ -325,7 +252,7 @@ index 7651676e72fcec52d7c1f9f7d7b6f9e585015c4d..ed3c5ad51ec0b9a1997e732e11db99ce } } -+ // Leaf start - Async Avoid Entity Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -353,20 +280,20 @@ index 7651676e72fcec52d7c1f9f7d7b6f9e585015c4d..ed3c5ad51ec0b9a1997e732e11db99ce + z + ); + } -+ // Leaf end - Async Avoid Entity Finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return !this.pathNav.isDone(); diff --git a/net/minecraft/world/entity/ai/goal/BegGoal.java b/net/minecraft/world/entity/ai/goal/BegGoal.java -index 6f7767d1ef5ee20338a334d85ad58dab9f8c4d1b..9f2658f49640c4f5c2de0c2810b3042b385f688a 100644 +index 6f7767d1ef5ee20338a334d85ad58dab9f8c4d1b..75dfa51d350bf767b269670c78d9a6253491acc7 100644 --- a/net/minecraft/world/entity/ai/goal/BegGoal.java +++ b/net/minecraft/world/entity/ai/goal/BegGoal.java @@ -27,8 +27,43 @@ public class BegGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.LOOK)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.wolf.getGoalCtx().result() instanceof Player target)) return false; + if (target == null) return false; @@ -390,11 +317,11 @@ index 6f7767d1ef5ee20338a334d85ad58dab9f8c4d1b..9f2658f49640c4f5c2de0c2810b3042b + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -402,7 +329,7 @@ index 6f7767d1ef5ee20338a334d85ad58dab9f8c4d1b..9f2658f49640c4f5c2de0c2810b3042b + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding this.player = this.level.getNearestPlayer(this.begTargeting, this.wolf); return this.player != null && this.playerHoldingInteresting(this.player); } @@ -411,16 +338,16 @@ index 6f7767d1ef5ee20338a334d85ad58dab9f8c4d1b..9f2658f49640c4f5c2de0c2810b3042b } - private boolean playerHoldingInteresting(Player player) { -+ private static boolean playerHoldingInteresting(Player player) { // Leaf start - Async Target Finding - static ++ private static boolean playerHoldingInteresting(Player player) { // Leaf start - Async target finding - static for (InteractionHand interactionHand : InteractionHand.values()) { ItemStack itemInHand = player.getItemInHand(interactionHand); - if (itemInHand.is(Items.BONE) || this.wolf.isFood(itemInHand)) { -+ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { // Leaf end - Async Target Finding ++ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { // Leaf end - Async target finding return true; } } diff --git a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java -index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d657ccaa96c 100644 +index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..892e22b80d8c98ea2954b4024ba434da5a1abffa 100644 --- a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java @@ -52,6 +52,13 @@ public class CatLieOnBedGoal extends MoveToBlockGoal { @@ -428,18 +355,18 @@ index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d65 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); -+ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); // Leaf - Async search block - diff on change ++ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.CatLie; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java -index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d35a172a3b 100644 +index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..79e71a41245028042b8ac5a56cd39bd0940c37f5 100644 --- a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java @@ -44,14 +44,21 @@ public class CatSitOnBlockGoal extends MoveToBlockGoal { @@ -447,11 +374,11 @@ index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d3 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - if (!level.isEmptyBlock(pos.above())) { -+ if (!level.isEmptyBlock(pos.above())) { // Leaf - Async search block - diff on change ++ if (!level.isEmptyBlock(pos.above())) { // Leaf - Async target finding - diff on change return false; } else { - BlockState blockState = level.getBlockState(pos); -+ BlockState blockState = level.getBlockState(pos); // Leaf - Async search block - diff on change ++ BlockState blockState = level.getBlockState(pos); // Leaf - Async target finding - diff on change return blockState.is(Blocks.CHEST) ? ChestBlockEntity.getOpenCount(level, pos) < 1 : blockState.is(Blocks.FURNACE) && blockState.getValue(FurnaceBlock.LIT) @@ -459,22 +386,22 @@ index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d3 } } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.CatSit; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java -index f7dcd341444059f8fb9708e9a21b5d8ace6b9cf9..b5571b7deb1645d88493c9fae866fd3726666754 100644 +index f7dcd341444059f8fb9708e9a21b5d8ace6b9cf9..dc2f0105b1f368e01bbbfc7c68a58e0012dd8736 100644 --- a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java @@ -23,8 +23,47 @@ public class FollowBoatGoal extends Goal { this.mob = mob; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -500,10 +427,10 @@ index f7dcd341444059f8fb9708e9a21b5d8ace6b9cf9..b5571b7deb1645d88493c9fae866fd37 + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding @Override public boolean canUse() { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -514,7 +441,7 @@ index f7dcd341444059f8fb9708e9a21b5d8ace6b9cf9..b5571b7deb1645d88493c9fae866fd37 + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.mob.level().getEntitiesOfClass(AbstractBoat.class, this.mob.getBoundingBox().inflate(5.0)); boolean flag = false; @@ -523,19 +450,19 @@ index f7dcd341444059f8fb9708e9a21b5d8ace6b9cf9..b5571b7deb1645d88493c9fae866fd37 } - return this.following != null && (Mth.abs(this.following.xxa) > 0.0F || Mth.abs(this.following.zza) > 0.0F) || flag; -+ return flag; // Leaf - Async Target Finding - move above ++ return flag; // Leaf - Async target finding - move above } @Override diff --git a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java -index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c9303917e194836 100644 +index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..66f69163ed8d36dcd0dec5603e72a88e8812d3e5 100644 --- a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java @@ -38,6 +38,15 @@ public class FollowMobGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async Follow Mob Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -543,7 +470,7 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 + getFollowingMobAsync(); + return false; + } -+ // Leaf end - Async Follow Mob Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.mob.level().getEntitiesOfClass(Mob.class, this.mob.getBoundingBox().inflate(this.areaSize), this.followPredicate); if (!entitiesOfClass.isEmpty()) { for (Mob mob : entitiesOfClass) { @@ -551,7 +478,7 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 return false; } -+ // Leaf start - Async Follow Mob Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Mob target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -579,20 +506,20 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..c2baf746a0697559dc391b6f8c930391 + return null; + }; + } -+ // Leaf end - Async Follow Mob Finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return this.followingMob != null && !this.navigation.isDone() && this.mob.distanceToSqr(this.followingMob) > this.stopDistance * this.stopDistance; diff --git a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java -index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270169330ef 100644 +index 3093f03d4f298bf39fec8bad2b6c22518774aea8..4eec8eda6ea1698529e0392bc75c07be5980f5fc 100644 --- a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java @@ -19,11 +19,56 @@ public class FollowParentGoal extends Goal { this.speedModifier = speedModifier; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.animal.getGoalCtx().result() instanceof Animal target)) return false; + var serverLevel = getServerLevel(animal); @@ -626,14 +553,14 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 + return target; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { if (this.animal.getAge() >= 0) { return false; } else { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -641,7 +568,7 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 + findTargetAsync(); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entitiesOfClass = this.animal .level() .getEntitiesOfClass((Class)this.animal.getClass(), this.animal.getBoundingBox().inflate(8.0, 4.0, 8.0)); @@ -649,12 +576,12 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270 if (animal == null) { return false; } else if (d < 9.0) { -+ // Leaf - Async Target Finding - diff on change ++ // Leaf - Async target finding - diff on change return false; } else { this.parent = animal; diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb506310de8461 100644 +index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01c8bb0ba8 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -26,13 +26,23 @@ public class GoalSelector { @@ -703,13 +630,13 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); // Paper end - Perf: optimize goal types if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) { -@@ -85,7 +96,131 @@ public class GoalSelector { +@@ -85,7 +96,136 @@ public class GoalSelector { return true; } + // Leaf start - Async target finding + public final boolean poll() { -+ if (this.ctxGoals == null || ctx.wake != null) { ++ if (ctxState == -1 || this.ctxGoals == null || ctx.wake != null || ctxGoals.length == 0) { + return false; + } + if (ctxState == 0) { @@ -728,7 +655,12 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 + ctx.state = true; + } + -+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); ++ for (Goal.Flag flag : GOAL_FLAG_VALUES) { ++ var goal = this.lockedFlags.get(flag); ++ if (goal != null && !goal.isRunning()) { ++ this.lockedFlags.remove(flag); ++ } ++ } + + ctxIndex = 0; + ctx.state = true; @@ -776,7 +708,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 + if (!ctx.state) { + switch (goal.getGoal()) { + case net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal t -> t.poll(); -+ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal t -> t.poll(); ++ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal t -> t.poll(); + default -> {} + } + } @@ -821,12 +753,12 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 public void tick() { + // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { -+ if (ctxState == -1) { -+ if (availableGoalsDirty || this.ctxGoals == null) { ++ if (this.ctxState == -1) { ++ if (this.availableGoalsDirty || this.ctxGoals == null) { + this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]); -+ availableGoalsDirty = false; ++ this.availableGoalsDirty = false; + } -+ ctxState = 0; ++ this.ctxState = 0; + } + return; + } @@ -835,7 +767,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams wrappedGoal.stop(); -@@ -116,6 +251,18 @@ public class GoalSelector { +@@ -116,6 +256,18 @@ public class GoalSelector { } public void tickRunningGoals(boolean tickAllRunning) { @@ -855,14 +787,14 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb5063 if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) { wrappedGoal.tick(); diff --git a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0bff40c42 100644 +index be59d0c27a83b329ec3f97c029cfb9c114e22472..888fd1919954acf3ec3c5d5a115dffc2e0fd3caf 100644 --- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java +++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java @@ -20,20 +20,83 @@ public class LlamaFollowCaravanGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + private @javax.annotation.Nullable Llama poll() { + if (!(this.llama.getGoalCtx().result() instanceof Llama target)) return null; + var serverLevel = getServerLevel(this.llama); @@ -911,13 +843,13 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 + return target; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { if (!this.llama.level().purpurConfig.llamaJoinCaravans || !this.llama.shouldJoinCaravan) return false; // Purpur - Llama API // Purpur - Config to disable Llama caravans if (!this.llama.isLeashed() && !this.llama.inCaravan()) { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + Llama llama = poll(); + double d = Double.MAX_VALUE; + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { @@ -928,20 +860,20 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 + d = this.llama.distanceToSqr(llama); + } + } else { -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding List entities = this.llama.level().getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0, 4.0, 9.0), entity1 -> { EntityType type = entity1.getType(); return type == EntityType.LLAMA || type == EntityType.TRADER_LLAMA; }); - Llama llama = null; - double d = Double.MAX_VALUE; -+ // Llama llama = null; // Leaf - Async Target Finding -+ // double d = Double.MAX_VALUE; // Leaf - Async Target Finding ++ // Llama llama = null; // Leaf - Async target finding ++ // double d = Double.MAX_VALUE; // Leaf - Async target finding for (Entity entity : entities) { Llama llama1 = (Llama)entity; - if (llama1.inCaravan() && !llama1.hasCaravanTail()) { -+ if (llama1.inCaravan() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change ++ if (llama1.inCaravan() && !llama1.hasCaravanTail()) { // Leaf - Async target finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { d = d1; @@ -950,7 +882,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 for (Entity entityx : entities) { Llama llama1 = (Llama)entityx; - if (llama1.isLeashed() && !llama1.hasCaravanTail()) { -+ if (llama1.isLeashed() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change ++ if (llama1.isLeashed() && !llama1.hasCaravanTail()) { // Leaf - Async target finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { d = d1; @@ -958,19 +890,19 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0 } } } -+ } // Leaf - Async Target Finding ++ } // Leaf - Async target finding if (llama == null) { return false; diff --git a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java -index 6463c3c9b08d6058f2843c225b08a40fc30a960b..98c2b4a298ada4b02afa55f991791d8696702181 100644 +index 6463c3c9b08d6058f2843c225b08a40fc30a960b..126bd98bc5980a2f1177bd7c74918b86a1f5bdce 100644 --- a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java +++ b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java @@ -48,32 +48,79 @@ public class LookAtPlayerGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -1060,19 +992,19 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..98c2b4a298ada4b02afa55f991791d86 - } + }; } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding @Override public boolean canContinueToUse() { diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e7c93afca 100644 +index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad51691a42 100644 --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java @@ -41,8 +41,60 @@ public abstract class MoveToBlockGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP)); } -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof BlockPos blockPos1)) return false; + if (!this.mob.level().hasChunkAt(blockPos1) @@ -1117,15 +1049,15 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + TurtleToWater, + TurtleLay, + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + @Override public boolean canUse() { -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (poll()) { + return true; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding if (this.nextStartTick > 0) { this.nextStartTick--; return false; @@ -1133,12 +1065,12 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e } protected boolean findNearestBlock() { -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) { + getBlockAsync(); + return false; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding int i = this.searchRange; int i1 = this.verticalSearchRange; BlockPos blockPos = this.mob.blockPosition(); @@ -1146,7 +1078,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e return false; } -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected static @javax.annotation.Nullable BlockPos findNearestBlockAsync( + final TypeToCheck ty, + @org.jetbrains.annotations.Nullable final net.minecraft.world.level.block.Block toRemove, @@ -1180,11 +1112,11 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + private static boolean isWithinRestriction(float restrictRadius, BlockPos restrictCenter, BlockPos pos) { + return restrictRadius == -1.0F || restrictCenter.distSqr(pos) < restrictRadius * restrictRadius; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + protected abstract boolean isValidTarget(LevelReader level, BlockPos pos); + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + protected abstract TypeToCheck typeToCheck(); + + private static boolean isValidTargetAsync( @@ -1245,18 +1177,18 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e + } + case null -> throw new IllegalStateException(); + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding + } } diff --git a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java -index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..0f2841a9681997c0d4b915284f7f5b385b1e172c 100644 +index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..d0e3e030bc5eacc304c523afcabd193ea86080e6 100644 --- a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java +++ b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java @@ -19,10 +19,20 @@ public class OfferFlowerGoal extends Goal { @Override public boolean canUse() { -+ // Leaf start - Async offer flower finding ++ // Leaf start - Async target finding if (!this.golem.level().isBrightOutside()) { return false; - } else if (this.golem.getRandom().nextInt(8000) != 0) { @@ -1270,7 +1202,7 @@ index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..0f2841a9681997c0d4b915284f7f5b38 + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + getVillagerAsync(); + return false; -+ // Leaf end - Async offer flower finding ++ // Leaf end - Async target finding } else { this.villager = getServerLevel(this.golem) .getNearestEntity( @@ -1279,7 +1211,7 @@ index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..0f2841a9681997c0d4b915284f7f5b38 } + -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.golem.getGoalCtx().result() instanceof Villager target)) return false; + var serverLevel = getServerLevel(this.golem); @@ -1306,13 +1238,13 @@ index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..0f2841a9681997c0d4b915284f7f5b38 + z + ); + } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding + @Override public boolean canContinueToUse() { return this.tick > 0; diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 16ec032d84f128fc44a836843fafef303f52b699..767dff2aa4c1d71cc3c22104366605486a5004b9 100644 +index 16ec032d84f128fc44a836843fafef303f52b699..4fe7961d031af0b2aa6b79d9f104ceb883edf301 100644 --- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java @@ -37,7 +37,14 @@ public class RemoveBlockGoal extends MoveToBlockGoal { @@ -1321,12 +1253,12 @@ index 16ec032d84f128fc44a836843fafef303f52b699..767dff2aa4c1d71cc3c2210436660548 return false; - } else if (this.nextStartTick > 0) { + } -+ // Leaf start - async search block ++ // Leaf start - Async target finding + if (poll()) { + this.nextStartTick = reducedTickDelay(20); + return true; + } -+ // Leaf end - async search block ++ // Leaf end - Async target finding + if (this.nextStartTick > 0) { this.nextStartTick--; return false; @@ -1336,27 +1268,27 @@ index 16ec032d84f128fc44a836843fafef303f52b699..767dff2aa4c1d71cc3c2210436660548 ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks return chunk != null - && chunk.getBlockState(pos).is(this.blockToRemove) -+ && chunk.getBlockState(pos).is(this.blockToRemove) // Leaf - Async search block - diff on change ++ && chunk.getBlockState(pos).is(this.blockToRemove) // Leaf - Async target finding - diff on change && chunk.getBlockState(pos.above()).isAir() && chunk.getBlockState(pos.above(2)).isAir(); } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.RemoveBlock; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java -index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50e9e62b34 100644 +index f88f618d34fb343b31de3af1a875d6633703df71..4bbd83c702a818b48313698919dc9a85392707f6 100644 --- a/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java @@ -36,12 +36,51 @@ public class TemptGoal extends Goal { this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity)); } -+ // Leaf start - Async Tempt Finding ++ // Leaf start - Async target finding + private boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); @@ -1375,14 +1307,14 @@ index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50 + .copy(); + ctx.wake = () -> serverLevel.getNearestPlayer(conditions, mob); + } -+ // Leaf end - Async Tempt Finding ++ // Leaf end - Async target finding @Override public boolean canUse() { if (this.calmDown > 0) { this.calmDown--; return false; } else { -+ // Leaf start - Async Tempt Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (poll()) { + if (this.player != null) { @@ -1400,28 +1332,19 @@ index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50 + return false; + } + } -+ // Leaf end - Async Tempt Finding ++ // Leaf end - Async target finding this.player = getServerLevel(this.mob) .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); // CraftBukkit start diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..6e752caa969891fa7f44b69ab58fca5434bb1aa9 100644 +index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..9054eb373de510f7949f7070cfe69ad2fe25ea3b 100644 --- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -@@ -16,7 +16,7 @@ public class DefendVillageTargetGoal extends TargetGoal { - private final IronGolem golem; - @Nullable - private LivingEntity potentialTarget; -- private final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); -+ private static final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); // Leaf - Async Target Finding - static - - public DefendVillageTargetGoal(IronGolem golem) { - super(golem, false, true); @@ -24,8 +24,49 @@ public class DefendVillageTargetGoal extends TargetGoal { this.setFlags(EnumSet.of(Goal.Flag.TARGET)); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); @@ -1451,7 +1374,7 @@ index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..6e752caa969891fa7f44b69ab58fca54 + return null; + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { @@ -1477,7 +1400,7 @@ index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..6e752caa969891fa7f44b69ab58fca54 @Override diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1ec99988b7 100644 +index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..412fc8e049ba3763314ec2a56dce378cb0e4cc5f 100644 --- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java @@ -73,6 +73,46 @@ public class HurtByTargetGoal extends TargetGoal { @@ -1485,7 +1408,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e double followDistance = this.getFollowDistance(); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followDistance, 10.0, followDistance); + -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var self = this.mob; + final var ctx = self.getGoalCtx(); @@ -1522,7 +1445,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e + }; + return; + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + List entitiesOfClass = this.mob .level() @@ -1532,7 +1455,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e mob = (Mob)var5.next(); if (this.mob != mob - && mob.getTarget() == null -+ && mob.getTarget() == null // Leaf - Async alert other - diff on change ++ && mob.getTarget() == null // Leaf - Async target finding - diff on change && (!(this.mob instanceof TamableAnimal) || ((TamableAnimal)this.mob).getOwner() == ((TamableAnimal)mob).getOwner()) && !mob.isAlliedTo(this.mob.getLastHurtByMob())) { if (this.toIgnoreAlert == null) { @@ -1541,7 +1464,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e boolean flag = false; - for (Class clazz : this.toIgnoreAlert) { -+ for (Class clazz : this.toIgnoreAlert) { // Leaf - Async alert other - diff on change ++ for (Class clazz : this.toIgnoreAlert) { // Leaf - Async target finding - diff on change if (mob.getClass() == clazz) { flag = true; break; @@ -1549,7 +1472,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e } } -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + public void poll() { + if (!(this.mob.getGoalCtx().result() instanceof List toAlert)) return; + LivingEntity lastHurtByMob = this.mob.getLastHurtByMob(); @@ -1577,20 +1500,20 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e + } + } + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + protected void alertOther(Mob mob, LivingEntity target) { mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason } diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e1139ffda32d 100644 +index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..7fac18f9d41030f0e9a566fd1923ea79edde32b6 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java @@ -41,8 +41,43 @@ public class NearestAttackableTargetGoal extends TargetG this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector); } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); @@ -1618,7 +1541,7 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e113 + } + }; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public boolean canUse() { @@ -1635,13 +1558,13 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e113 protected void findTarget() { ServerLevel serverLevel = getServerLevel(this.mob); + -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + this.findTargetAsync(); + this.target = null; + return; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + if (this.targetType != Player.class && this.targetType != ServerPlayer.class) { this.target = serverLevel.getNearestEntity( @@ -1689,14 +1612,14 @@ index abf57494950f55bbd75f335f26736cb9e703c197..efd2418f56c36e7850edde483a2a4906 } } diff --git a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java -index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc7fca2dc4 100644 +index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..08a09dea0dd377adca22b4432cf8f57c3122ec02 100644 --- a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java @@ -37,6 +37,27 @@ public class ResetUniversalAngerTargetGoal extends G this.lastHurtByPlayerTimestamp = this.mob.getLastHurtByMobTimestamp(); this.mob.forgetCurrentTargetAndRefreshUniversalAnger(); if (this.alertOthersOfSameType) { -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var mob = this.mob; + final var ctx = mob.getGoalCtx(); @@ -1716,7 +1639,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc + }; + return; + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding this.getNearbyMobsOfSameType() .stream() .filter(mob -> mob != this.mob) @@ -1724,7 +1647,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc super.start(); } -+ // Leaf start - Async alert other ++ // Leaf start - Async target finding + public void poll() { + if (!(this.mob.getGoalCtx().result() instanceof List toStop)) return; + for (var neutralMob : toStop) { @@ -1733,10 +1656,10 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc + } + } + } -+ // Leaf end - Async alert other ++ // Leaf end - Async target finding + private List getNearbyMobsOfSameType() { -+ // Leaf - Async alert other - diff on change ++ // Leaf - Async target finding - diff on change double attributeValue = this.mob.getAttributeValue(Attributes.FOLLOW_RANGE); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(attributeValue, 10.0, attributeValue); return this.mob.level().getEntitiesOfClass((Class)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS); @@ -1781,7 +1704,7 @@ index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..6fa0b8defbd1d06b3bf5d9b32ffd08f3 // Gale start - Petal - reduce line of sight cache lookups - merge sets int cached = this.seen.get(id); diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java -index ff20a6e9745c7724dfae41d5868912c8cc19eb8e..9eb9b978e2cc8570d8b884603172f2718e770d93 100644 +index ff20a6e9745c7724dfae41d5868912c8cc19eb8e..3cc611051b67672d139652bd004e7b4c1ef40cc6 100644 --- a/net/minecraft/world/entity/animal/Fox.java +++ b/net/minecraft/world/entity/animal/Fox.java @@ -870,6 +870,11 @@ public class Fox extends Animal { @@ -1810,7 +1733,7 @@ index ff20a6e9745c7724dfae41d5868912c8cc19eb8e..9eb9b978e2cc8570d8b884603172f271 protected boolean isValidTarget(LevelReader level, BlockPos pos) { BlockState blockState = level.getBlockState(pos); - return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); -+ return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); // Leaf - Async search block - diff on change ++ return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); // Leaf - Async target finding - diff on change } @Override @@ -1819,24 +1742,24 @@ index ff20a6e9745c7724dfae41d5868912c8cc19eb8e..9eb9b978e2cc8570d8b884603172f271 super.start(); } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.FoxEat; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } class FoxFloatGoal extends FloatGoal { diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java -index 99d99d59ec0eb13dc40bc88bd70ad884bb9e2859..d0be031cedcc895b8cca8666f826628ac8ce6ab3 100644 +index 99d99d59ec0eb13dc40bc88bd70ad884bb9e2859..ab1377cd82186389743107dad7117b7e24dd2d6b 100644 --- a/net/minecraft/world/entity/animal/Panda.java +++ b/net/minecraft/world/entity/animal/Panda.java @@ -988,9 +988,18 @@ public class Panda extends Animal { @Override public boolean canUse() { -+ // Leaf start - Async look finding ++ // Leaf start - Async target finding + if (poll()) { + return true; + } @@ -1847,12 +1770,12 @@ index 99d99d59ec0eb13dc40bc88bd70ad884bb9e2859..d0be031cedcc895b8cca8666f826628a + getLookAsync(); + return false; + } -+ // Leaf end - Async look finding ++ // Leaf end - Async target finding if (this.lookAt == null) { ServerLevel serverLevel = getServerLevel(this.mob); if (this.lookAtType == Player.class) { diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java -index fd8026cf1d884e95e8260ad52d4e0bbad20b0fdf..7ea36f2de5ecad35651d5333235e079a28bd0101 100644 +index fd8026cf1d884e95e8260ad52d4e0bbad20b0fdf..0286ea5ca5dec0f54a3d45d729beff427ac48e71 100644 --- a/net/minecraft/world/entity/animal/Rabbit.java +++ b/net/minecraft/world/entity/animal/Rabbit.java @@ -669,7 +669,13 @@ public class Rabbit extends Animal { @@ -1860,13 +1783,13 @@ index fd8026cf1d884e95e8260ad52d4e0bbad20b0fdf..7ea36f2de5ecad35651d5333235e079a } - return super.canUse(); -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + if (this.wantsToRaid && !this.canRaid) { + return super.canUse(); + } else { + return false; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } @Override @@ -1875,7 +1798,7 @@ index fd8026cf1d884e95e8260ad52d4e0bbad20b0fdf..7ea36f2de5ecad35651d5333235e079a protected boolean isValidTarget(LevelReader level, BlockPos pos) { BlockState blockState = level.getBlockState(pos); - if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { -+ if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { // Leaf - Async search block - diff on change ++ if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { // Leaf - Async target finding - diff on change blockState = level.getBlockState(pos.above()); if (blockState.getBlock() instanceof CarrotBlock && ((CarrotBlock)blockState.getBlock()).isMaxAge(blockState)) { this.canRaid = true; @@ -1884,17 +1807,17 @@ index fd8026cf1d884e95e8260ad52d4e0bbad20b0fdf..7ea36f2de5ecad35651d5333235e079a return false; } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.RaidGarden; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } public static enum Variant implements StringRepresentable { diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java -index c84f63f064a7769761f75cdedaceacde858b9b4e..9b7d059bf68ff24dddedb16ec62a9b67e3ceace9 100644 +index c84f63f064a7769761f75cdedaceacde858b9b4e..376e58e9997c6700f6a6b74325ae31396ff21be6 100644 --- a/net/minecraft/world/entity/animal/Turtle.java +++ b/net/minecraft/world/entity/animal/Turtle.java @@ -482,8 +482,15 @@ public class Turtle extends Animal { @@ -1902,15 +1825,15 @@ index c84f63f064a7769761f75cdedaceacde858b9b4e..9b7d059bf68ff24dddedb16ec62a9b67 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.getBlockState(pos).is(Blocks.WATER); -+ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async search block - diff on change ++ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.TurtleToWater; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class TurtleLayEggGoal extends MoveToBlockGoal { @@ -1919,20 +1842,20 @@ index c84f63f064a7769761f75cdedaceacde858b9b4e..9b7d059bf68ff24dddedb16ec62a9b67 @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); -+ return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); // Leaf - Async search block - diff on change ++ return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); // Leaf - Async target finding - diff on change + } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.TurtleLay; } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables diff --git a/net/minecraft/world/entity/animal/wolf/Wolf.java b/net/minecraft/world/entity/animal/wolf/Wolf.java -index 936ee9e80239ad965be75ceeb38d5248243e9c4e..cdb6781b319559ea23bad3b371a91d49cfc8adcc 100644 +index 936ee9e80239ad965be75ceeb38d5248243e9c4e..1a8cc61a67f92429ac49dc581b1c7f8e83389344 100644 --- a/net/minecraft/world/entity/animal/wolf/Wolf.java +++ b/net/minecraft/world/entity/animal/wolf/Wolf.java @@ -723,7 +723,7 @@ public class Wolf extends TamableAnimal implements NeutralMob { @@ -1940,12 +1863,12 @@ index 936ee9e80239ad965be75ceeb38d5248243e9c4e..cdb6781b319559ea23bad3b371a91d49 @Override public boolean isFood(ItemStack stack) { - return stack.is(ItemTags.WOLF_FOOD); -+ return stack.is(ItemTags.WOLF_FOOD); // Leaf - Async Target Finding - diff on change ++ return stack.is(ItemTags.WOLF_FOOD); // Leaf - Async target finding - diff on change } @Override diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java -index 2e04078664cd723e3e0c80565e4b6e6416b13901..ed790a407b4be9e2f7fcb8cf36b8d03c32864a59 100644 +index 2e04078664cd723e3e0c80565e4b6e6416b13901..12dce38c2377c1cea4cb33ac9f1fa2f204b6e12b 100644 --- a/net/minecraft/world/entity/monster/Drowned.java +++ b/net/minecraft/world/entity/monster/Drowned.java @@ -397,7 +397,7 @@ public class Drowned extends Zombie implements RangedAttackMob { @@ -1953,7 +1876,7 @@ index 2e04078664cd723e3e0c80565e4b6e6416b13901..ed790a407b4be9e2f7fcb8cf36b8d03c protected boolean isValidTarget(LevelReader level, BlockPos pos) { BlockPos blockPos = pos.above(); - return level.isEmptyBlock(blockPos) && level.isEmptyBlock(blockPos.above()) && level.getBlockState(pos).entityCanStandOn(level, pos, this.drowned); -+ return level.isEmptyBlock(blockPos) && level.isEmptyBlock(blockPos.above()) && level.getBlockState(pos).entityCanStandOn(level, pos, this.drowned); // Leaf - Async search block - diff on change ++ return level.isEmptyBlock(blockPos) && level.isEmptyBlock(blockPos.above()) && level.getBlockState(pos).entityCanStandOn(level, pos, this.drowned); // Leaf - Async target finding - diff on change } @Override @@ -1962,24 +1885,24 @@ index 2e04078664cd723e3e0c80565e4b6e6416b13901..ed790a407b4be9e2f7fcb8cf36b8d03c super.stop(); } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.Drowned; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class DrownedGoToWaterGoal extends Goal { diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java -index 16886178079a096329d06f40d502012b6fa473e0..36d5621d4d92c86a6edbd088ce5e5a246cdbe5cb 100644 +index 16886178079a096329d06f40d502012b6fa473e0..4299a1c4121e90118b26d19424d3075050cf4cb0 100644 --- a/net/minecraft/world/entity/monster/EnderMan.java +++ b/net/minecraft/world/entity/monster/EnderMan.java @@ -592,10 +592,34 @@ public class EnderMan extends Monster implements NeutralMob { @Override public boolean canUse() { -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (poll()) { + return true; @@ -1992,12 +1915,12 @@ index 16886178079a096329d06f40d502012b6fa473e0..36d5621d4d92c86a6edbd088ce5e5a24 + ctx.wake = () -> level.getNearestPlayer(cond, enderman); + return false; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding this.pendingTarget = getServerLevel(this.enderman).getNearestPlayer(this.startAggroTargetConditions.range(this.getFollowDistance()), this.enderman); return this.pendingTarget != null; } -+ // Leaf start - Async Target Finding ++ // Leaf start - Async target finding + protected boolean poll() { + if (!(this.mob.getGoalCtx().result() instanceof Player player)) return false; + var serverLevel = getServerLevel(this.enderman); @@ -2005,13 +1928,13 @@ index 16886178079a096329d06f40d502012b6fa473e0..36d5621d4d92c86a6edbd088ce5e5a24 + this.pendingTarget = player; + return true; + } -+ // Leaf end - Async Target Finding ++ // Leaf end - Async target finding + @Override public void start() { this.aggroTime = this.adjustedTickDelay(5); diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java -index e1717b5c854aa81fdd7b7e715d7c3498d9f86072..3627e7479b4deea28e268245410ec4cd48f24e9e 100644 +index e1717b5c854aa81fdd7b7e715d7c3498d9f86072..727effd31644432f9da04ee4e3aaa41ce45d6a2e 100644 --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java @@ -551,8 +551,15 @@ public class Strider extends Animal implements ItemSteerable { @@ -2019,31 +1942,23 @@ index e1717b5c854aa81fdd7b7e715d7c3498d9f86072..3627e7479b4deea28e268245410ec4cd @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { - return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); -+ return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); // Leaf - Async search block - diff on change ++ return level.getBlockState(pos).is(Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(PathComputationType.LAND); // Leaf - Async target finding - diff on change } + -+ // Leaf start - Async search block ++ // Leaf start - Async target finding + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.Strider; + } -+ // Leaf end - Async search block ++ // Leaf end - Async target finding } static class StriderPathNavigation extends GroundPathNavigation { diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 4158bbe0740fe2971a9e857cb4cad08ee465576a..e380cc68d0d88d983a1b7b1d9ef4ec8ef307761a 100644 +index 4158bbe0740fe2971a9e857cb4cad08ee465576a..48ea77151695eb6958bfd31bac99a9f1c050b240 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -1531,6 +1531,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl - } - // Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - do not bother with condition work / make configurable - // Paper end - rewrite chunk system -+ ((ServerLevel) this).leafMidTickTasks(); // Leaf - Async target finding - } - } - this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals -@@ -1799,9 +1800,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1799,9 +1799,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @Override public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate predicate) { @@ -2051,9 +1966,9 @@ index 4158bbe0740fe2971a9e857cb4cad08ee465576a..e380cc68d0d88d983a1b7b1d9ef4ec8e - ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs) - List list = Lists.newArrayList(); + // Leaf start - Async target finding -+ //if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf start - SparklyPaper - parallel world ticking mod (make configurable) -+ // ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs) -+ //List list = Lists.newArrayList(); // Leaf - Async target finding - unused ++ // if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf start - SparklyPaper - parallel world ticking mod (make configurable) ++ // ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs) ++ // List list = Lists.newArrayList(); // Leaf - Async target finding - unused + // Leaf end - Async target finding // Paper start - rewrite chunk system diff --git a/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch b/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch index a1fe2d5a..2fba7230 100644 --- a/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch +++ b/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch @@ -100,7 +100,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194 - // Paper end - detailed watchdog information } diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 9dd6205e1cdd2124ab9d91f0a1e344eb6aa1fb2e..d8ae228fa4dfb265b628e83936f297f88c74aa57 100644 +index fc86e900e41305287a6cc6d766184c6e28d6189b..6fd7e881bcfc7df2e4ac7abb99504c8194470e96 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -622,8 +622,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -117,10 +117,10 @@ index 9dd6205e1cdd2124ab9d91f0a1e344eb6aa1fb2e..d8ae228fa4dfb265b628e83936f297f8 for (LevelChunk levelChunk : list) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index c0044f4013520fd617ec365012b10862571744f3..14d23006d3ec15bb3ec6f976bff6c0975662c69d 100644 +index 224a032e8992f104ad9380182ed67c316c93274e..7d34862d15360940e12b9c0f131ecffdb2a0a146 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1518,13 +1518,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1508,13 +1508,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - log detailed entity tick information public void tickNonPassenger(Entity entity) { @@ -134,7 +134,7 @@ index c0044f4013520fd617ec365012b10862571744f3..14d23006d3ec15bb3ec6f976bff6c097 entity.setOldPosAndRot(); entity.tickCount++; entity.totalEntityAge++; // Paper - age-like counter for all entities -@@ -1537,13 +1531,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1527,13 +1521,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (Entity entity1 : entity.getPassengers()) { this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java index 780e2678..371f54e5 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java @@ -1,6 +1,5 @@ package org.dreeam.leaf.async.ai; -import it.unimi.dsi.fastutil.ints.IntArrayList; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; @@ -10,85 +9,54 @@ import org.dreeam.leaf.config.modules.async.AsyncTargetFinding; import org.dreeam.leaf.util.queue.SpscIntQueue; import java.util.OptionalInt; -import java.util.concurrent.locks.LockSupport; public class AsyncGoalExecutor { protected static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal"); protected final SpscIntQueue queue; - protected final SpscIntQueue wake; - protected final IntArrayList submit; private final ServerLevel world; - private long midTickCount = 0L; - public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel world) { + public AsyncGoalExecutor(ServerLevel world) { this.world = world; this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize); - this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize); - this.submit = new IntArrayList(); } - boolean wake(int id) { - Entity entity = this.world.getEntities().get(id); - if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) { - return false; - } - mob.goalSelector.ctx.wake(); - mob.targetSelector.ctx.wake(); - return true; - } - - public final void submit(int entityId) { - this.submit.add(entityId); - } - - public final void tick() { - batchSubmit(); + boolean wakeAll() { + boolean success = false; while (true) { - OptionalInt result = this.wake.recv(); + OptionalInt result = queue.recv(); if (result.isEmpty()) { break; } int id = result.getAsInt(); - if (poll(id) && !this.queue.send(id)) { - do { - wake(id); - } while (poll(id)); - } + success = true; + wake(id); } + return success; } - private void batchSubmit() { - if (submit.isEmpty()) { + public void tickMob(Mob mob) { + if (!poll(mob)) { return; } - int[] raw = submit.elements(); - int size = submit.size(); - for (int i = 0; i < size; i++) { - int id = raw[i]; - if (poll(id) && !this.queue.send(id)) { - do { - wake(id); - } while (poll(id)); - } + int entityId = mob.getId(); + if (!this.queue.send(entityId)) { + do { + wake(entityId); + } while (poll(mob)); } - this.submit.clear(); } - public final void midTick() { - if (AsyncTargetFinding.threshold <= 0L || (midTickCount % AsyncTargetFinding.threshold) == 0L) { - batchSubmit(); - } - - midTickCount += 1; - } - - private boolean poll(int id) { + private void wake(int id) { Entity entity = this.world.getEntities().get(id); if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) { - return false; + return; } + mob.goalSelector.ctx.wake(); + mob.targetSelector.ctx.wake(); + } + private boolean poll(Mob mob) { try { mob.tickingTarget = true; boolean a = mob.targetSelector.poll(); @@ -97,8 +65,7 @@ public class AsyncGoalExecutor { return a || b; } catch (Exception e) { LOGGER.error("Exception while polling", e); - // retry - return true; + return false; } } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java index e989adbf..4012e4cf 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java @@ -22,26 +22,11 @@ public class AsyncGoalThread extends Thread { while (RUNNING) { boolean retry = false; for (ServerLevel level : server.getAllLevels()) { - var exec = level.asyncGoalExecutor; - while (true) { - OptionalInt result = exec.queue.recv(); - if (result.isEmpty()) { - break; - } - int id = result.getAsInt(); - retry = true; - if (exec.wake(id)) { - while (!exec.wake.send(id)) { - Thread.onSpinWait(); - } - } - } - - Thread.yield(); + retry |= level.asyncGoalExecutor.wakeAll(); } if (!retry) { - LockSupport.parkNanos(10_000L); + LockSupport.parkNanos(1_000_000L); } } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java index ec1a8a7b..101b9eaf 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java @@ -16,7 +16,6 @@ public class AsyncTargetFinding extends ConfigModules { public static boolean searchBlock = true; public static boolean searchEntity = true; public static int queueSize = 4096; - public static long threshold = 10L; private static boolean asyncTargetFindingInitialized; @Override @@ -36,21 +35,17 @@ public class AsyncTargetFinding extends ConfigModules { enabled = config.getBoolean(getBasePath() + ".enabled", enabled); // Disable if parallel world ticking is enabled, as they are incompatible. if (enabled && SparklyPaperParallelWorldTicking.enabled) { - LeafConfig.LOGGER.warn("Async Target Finding is incompatible with Parallel World Ticking. Disabling Async Target Finding automatically."); + LeafConfig.LOGGER.warn("Async target finding is incompatible with Parallel World Ticking. Disabling Async target finding automatically."); enabled = false; } alertOther = config.getBoolean(getBasePath() + ".async-alert-other", true); searchBlock = config.getBoolean(getBasePath() + ".async-search-block", true); searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true); queueSize = config.getInt(getBasePath() + ".queue-size", 0); - threshold = config.getLong(getBasePath() + ".threshold", 0); if (queueSize <= 0) { queueSize = 4096; } - if (threshold == 0L) { - threshold = 10L; - } if (!enabled) { alertOther = false; searchEntity = false; From 731950179b03e6448ec5bf51a73d2f0c6a56f690 Mon Sep 17 00:00:00 2001 From: Taiyou <77050201+Taiyou06@users.noreply.github.com> Date: Wed, 18 Jun 2025 06:56:23 +0200 Subject: [PATCH 11/26] Optimize random tick (#359) * optimize random tick * rebase * fix random tick chance check * add back zero check fix always tick on first tick * optimize random check * cleanup * remove 0 to 2 random on amount chosen * cleanup * add queue and reuse block count * reduce LevelChunkSection#tickingBlocks memory overhead * Revert "reduce LevelChunkSection#tickingBlocks memory overhead" This reverts commit 942376481bf775324ce6349766200b5f044bffa0. * fix overflow * [ci skip] rebuild patches --------- Co-authored-by: hayanesuru --- .../features/0280-optimize-random-tick.patch | 105 +++++++++++ ...tion.patch => 0281-Paw-optimization.patch} | 8 +- .../modules/opt/OptimizeRandomTick.java | 20 +++ .../dreeam/leaf/world/RandomTickSystem.java | 164 ++++++++++++++++++ 4 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 leaf-server/minecraft-patches/features/0280-optimize-random-tick.patch rename leaf-server/minecraft-patches/features/{0280-Paw-optimization.patch => 0281-Paw-optimization.patch} (99%) create mode 100644 leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java create mode 100644 leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java diff --git a/leaf-server/minecraft-patches/features/0280-optimize-random-tick.patch b/leaf-server/minecraft-patches/features/0280-optimize-random-tick.patch new file mode 100644 index 00000000..108f600b --- /dev/null +++ b/leaf-server/minecraft-patches/features/0280-optimize-random-tick.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hayanesuru +Date: Fri, 6 Jun 2025 20:46:10 +0900 +Subject: [PATCH] optimize random tick + + +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index fc86e900e41305287a6cc6d766184c6e28d6189b..9286312e11b98e4873f1ca13cf210feadcd6a2d7 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -632,6 +632,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } finally { + list.clear(); + } ++ this.level.randomTickSystem.tick(this.level); // Leaf - optimize random tick + + this.iterateTickingChunksFaster(); // Paper - chunk tick iteration optimisations + if (_boolean) { +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index 224a032e8992f104ad9380182ed67c316c93274e..07f6da45a88e1630ca4249bb134fce1f95d2c39c 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -1110,6 +1110,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking + ++ public org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting + ChunkPos pos = chunk.getPos(); +@@ -1125,7 +1126,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } // Paper - Option to disable ice and snow + + if (randomTickSpeed > 0) { +- this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking ++ if (org.dreeam.leaf.config.modules.opt.OptimizeRandomTick.enabled) randomTickSystem.tickChunk(this.simpleRandom, chunk, randomTickSpeed); // Leaf - optimize random tick ++ else this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking // Leaf - optimize random tick + } + } + +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index 31f19dfe16e270b55f3b44754c97ed8d9fa422cf..31c6c035aca5400a5c0a030bfe5334545e2a4bca 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -150,6 +150,48 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + } + // Gale end - Airplane - optimize random calls in chunk ticking - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively + ++ // Leaf start - optimize random tick ++ private boolean leaf$tickingBlocksDirty = true; ++ private int leaf$tickingBlocksCount; ++ private int leaf$firstTickingSectionIndex = -1; ++ public final int leaf$tickingBlocksCount() { ++ if (!leaf$tickingBlocksDirty) { ++ return leaf$tickingBlocksCount; ++ } ++ leaf$tickingBlocksDirty = false; ++ int sum = 0; ++ leaf$firstTickingSectionIndex = -1; ++ for (int i = 0; i < sections.length; i++) { ++ LevelChunkSection section = sections[i]; ++ int size = section.moonrise$getTickingBlockList().size(); ++ if (size != 0 && leaf$firstTickingSectionIndex == -1) { ++ leaf$firstTickingSectionIndex = i; ++ } ++ sum += size; ++ } ++ leaf$tickingBlocksCount = sum; ++ return sum; ++ } ++ public final java.util.OptionalLong leaf$getTickingPos(int idx) { ++ if (leaf$firstTickingSectionIndex != -1) { ++ for (int i = leaf$firstTickingSectionIndex; i < sections.length; i++) { ++ LevelChunkSection section = sections[i]; ++ var l = section.moonrise$getTickingBlockList(); ++ int size = l.size(); ++ if (idx < size) { ++ short loc = l.getRaw(idx); ++ int x = (loc & 15) | (chunkPos.x << 4); ++ int y = (loc >>> 8) | ((getMinSectionY() + i) << 4); ++ int z = ((loc >>> 4) & 15) | (chunkPos.z << 4); ++ return java.util.OptionalLong.of(BlockPos.asLong(x, y, z)); ++ } ++ idx -= size; ++ } ++ } ++ leaf$tickingBlocksDirty = true; ++ return java.util.OptionalLong.empty(); ++ } ++ // Leaf end - optimize random tick + public LevelChunk(Level level, ChunkPos pos) { + this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); + } +@@ -414,6 +456,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + if (blockState == state) { + return null; + } else { ++ // Leaf start - optimize random tick ++ if (blockState.isRandomlyTicking() != state.isRandomlyTicking()) { ++ leaf$tickingBlocksDirty = true; ++ } ++ // Leaf end - optimize random tick + Block block = state.getBlock(); + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state); + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state); diff --git a/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch b/leaf-server/minecraft-patches/features/0281-Paw-optimization.patch similarity index 99% rename from leaf-server/minecraft-patches/features/0280-Paw-optimization.patch rename to leaf-server/minecraft-patches/features/0281-Paw-optimization.patch index 2fba7230..4e9029bb 100644 --- a/leaf-server/minecraft-patches/features/0280-Paw-optimization.patch +++ b/leaf-server/minecraft-patches/features/0281-Paw-optimization.patch @@ -100,7 +100,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194 - // Paper end - detailed watchdog information } diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index fc86e900e41305287a6cc6d766184c6e28d6189b..6fd7e881bcfc7df2e4ac7abb99504c8194470e96 100644 +index 9286312e11b98e4873f1ca13cf210feadcd6a2d7..014fb76ad0e57048d036659bd89e628fd81a0190 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -622,8 +622,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -117,10 +117,10 @@ index fc86e900e41305287a6cc6d766184c6e28d6189b..6fd7e881bcfc7df2e4ac7abb99504c81 for (LevelChunk levelChunk : list) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 224a032e8992f104ad9380182ed67c316c93274e..7d34862d15360940e12b9c0f131ecffdb2a0a146 100644 +index 07f6da45a88e1630ca4249bb134fce1f95d2c39c..9fbaafaf5df6e003742cdea55da732cc7e602866 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1508,13 +1508,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1510,13 +1510,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - log detailed entity tick information public void tickNonPassenger(Entity entity) { @@ -134,7 +134,7 @@ index 224a032e8992f104ad9380182ed67c316c93274e..7d34862d15360940e12b9c0f131ecffd entity.setOldPosAndRot(); entity.tickCount++; entity.totalEntityAge++; // Paper - age-like counter for all entities -@@ -1527,13 +1521,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1529,13 +1523,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (Entity entity1 : entity.getPassengers()) { this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java new file mode 100644 index 00000000..525bcac7 --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeRandomTick.java @@ -0,0 +1,20 @@ +package org.dreeam.leaf.config.modules.opt; + +import org.dreeam.leaf.config.ConfigModules; +import org.dreeam.leaf.config.EnumConfigCategory; +import org.dreeam.leaf.config.annotations.Experimental; + +public class OptimizeRandomTick extends ConfigModules { + + public String getBasePath() { + return EnumConfigCategory.PERF.getBaseKeyName() + ".optimise-random-tick"; + } + + @Experimental + public static boolean enabled = false; + + @Override + public void onLoaded() { + enabled = config.getBoolean(getBasePath(), enabled); + } +} diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java new file mode 100644 index 00000000..fdcaad27 --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java @@ -0,0 +1,164 @@ +package org.dreeam.leaf.world; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.material.FluidState; + +import java.util.OptionalLong; + +public final class RandomTickSystem { + private static final long SCALE = 0x100000L; + private static final long CHUNK_BLOCKS = 4096L; + + /// reduce unnecessary sampling and block counting + private static final long TICK_MASK = 0b11L; + private static final long TICK_MUL = 4L; + private static final int BITS_STEP = 2; + private static final int BITS_MAX = 60; + + private final LongArrayList queue = new LongArrayList(); + private final LongArrayList samples = new LongArrayList(); + private final LongArrayList weights = new LongArrayList(); + private long weightsSum = 0L; + + private int bits = 60; + private long cacheRandom = 0L; + + public void tick(ServerLevel world) { + if (weights.isEmpty() || samples.isEmpty()) { + return; + } + + final var random = world.simpleRandom; + final long chosen; + if (((weightsSum % SCALE) >= boundedNextLong(random, SCALE))) { + chosen = weightsSum / SCALE + 1L; + } else { + chosen = weightsSum / SCALE; + } + if (chosen == 0L) { + return; + } + + final long spoke = weightsSum / chosen; + if (spoke == 0L) { + return; + } + + final long[] weightsRaw = weights.elements(); + final long[] samplesRaw = samples.elements(); + + long accumulated = weightsRaw[0]; + long current = boundedNextLong(random, spoke); + int i = 0; + while (current < weightsSum) { + while (accumulated < current) { + i += 1; + accumulated += weightsRaw[i]; + } + queue.add(samplesRaw[i]); + current += spoke; + } + while (queue.size() < chosen) { + queue.add(samplesRaw[i]); + } + + long[] queueRaw = queue.elements(); + int j = 0; + int k; + for (k = queue.size() - 3; j < k; j += 4) { + final long packed1 = queueRaw[j]; + final long packed2 = queueRaw[j + 1]; + final long packed3 = queueRaw[j + 2]; + final long packed4 = queueRaw[j + 3]; + final LevelChunk chunk1 = getChunk(world, packed1); + final LevelChunk chunk2 = packed1 != packed2 ? getChunk(world, packed2) : chunk1; + final LevelChunk chunk3 = packed2 != packed3 ? getChunk(world, packed3) : chunk2; + final LevelChunk chunk4 = packed3 != packed4 ? getChunk(world, packed4) : chunk3; + if (chunk1 != null) tickBlock(world, chunk1, random); + if (chunk2 != null) tickBlock(world, chunk2, random); + if (chunk3 != null) tickBlock(world, chunk3, random); + if (chunk4 != null) tickBlock(world, chunk4, random); + } + for (k = queue.size(); j < k; j++) { + LevelChunk chunk = getChunk(world, queueRaw[j]); + if (chunk != null) tickBlock(world, chunk, random); + } + + weightsSum = 0L; + queue.clear(); + weights.clear(); + samples.clear(); + } + + private static LevelChunk getChunk(ServerLevel world, long packed) { + return world.chunkSource.getChunkAtIfLoadedImmediately((int) packed, (int) (packed >> 32)); + } + + private static void tickBlock(ServerLevel world, LevelChunk chunk, RandomSource random) { + OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(chunk.leaf$tickingBlocksCount())); + if (optionalPos.isEmpty()) { + return; + } + BlockPos pos = BlockPos.of(optionalPos.getAsLong()); + BlockState state = chunk.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); + state.randomTick(world, pos, random); + + final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294(); + if (doubleTickFluids) { + final FluidState fluidState = state.getFluidState(); + if (fluidState.isRandomlyTicking()) { + fluidState.randomTick(world, pos, random); + } + } + } + + public void tickChunk( + RandomSource random, + LevelChunk chunk, + long tickSpeed + ) { + if (this.bits == BITS_MAX) { + this.bits = 0; + this.cacheRandom = random.nextLong(); + } else { + this.bits += BITS_STEP; + } + if ((this.cacheRandom & (TICK_MASK << bits)) == 0L) { + long count = chunk.leaf$tickingBlocksCount(); + if (count != 0L) { + long weight = (TICK_MUL * tickSpeed * count * SCALE) / CHUNK_BLOCKS; + samples.add(chunk.getPos().longKey); + weights.add(weight); + weightsSum += weight; + } + } + } + + /** + * @param rng a random number generator to be used as a + * source of pseudorandom {@code long} values + * @param bound the upper bound (exclusive); must be greater than zero + * + * @return a pseudorandomly chosen {@code long} value + * + * @see java.util.random.RandomGenerator#nextLong(long) nextLong(bound) + */ + public static long boundedNextLong(RandomSource rng, long bound) { + final long m = bound - 1; + long r = rng.nextLong(); + if ((bound & m) == 0L) { + r &= m; + } else { + for (long u = r >>> 1; + u + m - (r = u % bound) < 0L; + u = rng.nextLong() >>> 1) + ; + } + return r; + } +} From 91a911a60f64d6264311f5091d9046c4acf6c7cf Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Thu, 19 Jun 2025 01:10:08 +0800 Subject: [PATCH 12/26] Fix powered rail range in optimized powered rail --- .../world/block/OptimizedPoweredRails.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java b/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java index f4f3c7be..7e34b2e1 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java @@ -20,8 +20,6 @@ public class OptimizedPoweredRails { private static final int UPDATE_FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS; - private static int RAIL_POWER_LIMIT = 8; - private static final Object2BooleanOpenHashMap CHECKED_POS_POOL = new Object2BooleanOpenHashMap<>(); private static void giveShapeUpdate(Level level, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) { @@ -36,14 +34,6 @@ public class OptimizedPoweredRails { ); } - public static int getRailPowerLimit() { - return RAIL_POWER_LIMIT; - } - - public static void setRailPowerLimit(int powerLimit) { - RAIL_POWER_LIMIT = powerLimit; - } - public static void updateState(PoweredRailBlock self, BlockState state, Level level, BlockPos pos) { boolean shouldBePowered = level.hasNeighborSignal(pos) || findPoweredRailSignalFaster(self, level, pos, state, true, 0, CHECKED_POS_POOL) || @@ -97,7 +87,7 @@ public class OptimizedPoweredRails { private static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level level, BlockPos pos, BlockState state, boolean searchForward, int distance, Object2BooleanOpenHashMap checkedPos) { - if (distance >= RAIL_POWER_LIMIT - 1) return false; + if (distance >= level.purpurConfig.railActivationRange) return false; int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); @@ -203,7 +193,8 @@ public class OptimizedPoweredRails { private static void setRailPositionsPower(PoweredRailBlock self, Level level, BlockPos pos, Object2BooleanOpenHashMap checkedPos, int[] count, int i, Direction dir) { - for (int z = 1; z < RAIL_POWER_LIMIT; z++) { + final int railPowerLimit = level.purpurConfig.railActivationRange; + for (int z = 1; z < railPowerLimit; z++) { BlockPos newPos = pos.relative(dir, z); BlockState state = level.getBlockState(newPos); if (checkedPos.containsKey(newPos)) { @@ -229,7 +220,8 @@ public class OptimizedPoweredRails { int[] count, int i, Direction dir) { Object2BooleanOpenHashMap checkedPos = CHECKED_POS_POOL; checkedPos.clear(); - for (int z = 1; z < RAIL_POWER_LIMIT; z++) { + final int railPowerLimit = level.purpurConfig.railActivationRange; + for (int z = 1; z < railPowerLimit; z++) { BlockPos newPos = pos.relative(dir, z); BlockState state = level.getBlockState(newPos); if (!state.is(self) || !state.getValue(POWERED) || level.hasNeighborSignal(newPos) || From 82eaa5d3f33a50278042aa632bfee5d9d9437a0c Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Fri, 20 Jun 2025 03:22:06 +1400 Subject: [PATCH 13/26] Hide seed obfuscation key from spark --- .../src/main/java/org/dreeam/leaf/config/LeafConfig.java | 2 ++ .../config/modules/opt/FastBiomeManagerSeedObfuscation.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/LeafConfig.java b/leaf-server/src/main/java/org/dreeam/leaf/config/LeafConfig.java index 604140f4..e525e72f 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/LeafConfig.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/LeafConfig.java @@ -7,6 +7,7 @@ import net.minecraft.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dreeam.leaf.config.modules.misc.SentryDSN; +import org.dreeam.leaf.config.modules.opt.FastBiomeManagerSeedObfuscation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.bukkit.Bukkit; @@ -243,6 +244,7 @@ public class LeafConfig { List extraHidden = existing != null ? new ArrayList<>(Arrays.asList(existing.split(","))) : new ArrayList<>(); extraHidden.add(SentryDSN.sentryDsnConfigPath); // Hide Sentry DSN key + extraHidden.add(FastBiomeManagerSeedObfuscation.seedObfKeyPath); // Hide FastBiomeManagerSeedObfuscation key return extraHidden; } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastBiomeManagerSeedObfuscation.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastBiomeManagerSeedObfuscation.java index 0189e746..c49a688c 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastBiomeManagerSeedObfuscation.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastBiomeManagerSeedObfuscation.java @@ -15,6 +15,7 @@ public class FastBiomeManagerSeedObfuscation extends ConfigModules { @Experimental public static boolean enabled = false; public static long seedObfuscationKey = ThreadLocalRandom.current().nextLong(); + public static String seedObfKeyPath; @Override public void onLoaded() { @@ -26,7 +27,7 @@ public class FastBiomeManagerSeedObfuscation extends ConfigModules { """ **实验性功能** 将原版 BiomeManager 的 SHA-256 种子混淆换成 XXHash.""")); - seedObfuscationKey = config.getLong(getBasePath() + ".seed-obfuscation-key", seedObfuscationKey, + seedObfuscationKey = config.getLong(seedObfKeyPath = getBasePath() + ".seed-obfuscation-key", seedObfuscationKey, config.pickStringRegionBased( "Seed obfuscation key for XXHash.", "XXHash 的混淆种子.")); From d46c4bca937b2aa761a2573133c9f286d4a9349d Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Thu, 19 Jun 2025 22:13:24 +0800 Subject: [PATCH 14/26] Fetch all commits to fix download api --- .github/workflows/build-1215.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-1215.yml b/.github/workflows/build-1215.yml index 1a21f932..81f92a08 100644 --- a/.github/workflows/build-1215.yml +++ b/.github/workflows/build-1215.yml @@ -134,7 +134,7 @@ jobs: BRANCH="${{ github.ref_name }}" REPO_DIR="/root/Leaf-${BRANCH//\//-}" # Replace slashes with dashes to avoid directory issues - [ -d "$REPO_DIR/.git" ] && cd "$REPO_DIR" && git fetch origin && git checkout "$BRANCH" && git reset --hard "origin/$BRANCH" || git clone --branch "$BRANCH" --depth 1 https://github.com/Winds-Studio/Leaf "$REPO_DIR" + [ -d "$REPO_DIR/.git" ] && cd "$REPO_DIR" && git fetch origin && git checkout "$BRANCH" && git reset --hard "origin/$BRANCH" || git clone --branch "$BRANCH" https://github.com/Winds-Studio/Leaf "$REPO_DIR" # Proceed to insert the build into the API cd ~/api/cli From b559e1ed7254c27853ca492b57d512d86c60ac67 Mon Sep 17 00:00:00 2001 From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Fri, 20 Jun 2025 08:06:42 +1400 Subject: [PATCH 15/26] Add missing rewrite rules --- .../0062-Add-missing-rewrite-rules.patch | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch diff --git a/leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch b/leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch new file mode 100644 index 00000000..43921cad --- /dev/null +++ b/leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> +Date: Tue, 9 Nov 2077 00:00:00 +0800 +Subject: [PATCH] Add missing rewrite rules + +Tracking PR: https://github.com/PaperMC/asm-utils/pull/48 + +diff --git a/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java b/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java +index a3045afbc0cc057e99189b909367b21cf6a9e03f..2831b8b48a12815f8fb7e82327f654e90d1530a3 100644 +--- a/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java ++++ b/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java +@@ -22,7 +22,14 @@ public final class ReflectionRemapper { + private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create( + Opcodes.ASM9, + chain -> chain.then(new BaseReflectionRules(PAPER_REFLECTION_HOLDER).rules()) +- .then(DefineClassRule.create(PAPER_REFLECTION_HOLDER_DESC, true)), ++ // Leaf start - Add missing rewrite rules ++ .then( ++ io.papermc.asm.rules.RewriteRule.forOwnerClass(Class.class, rf -> { ++ rf.plainStaticRewrite(java.lang.constant.ClassDesc.of(PAPER_REFLECTION_HOLDER), b -> b ++ .match("forName").desc("(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;")); ++ }) ++ ).then(DefineClassRule.create(PAPER_REFLECTION_HOLDER_DESC, true)), ++ // Leaf end - Add missing rewrite rules + ClassInfoProvider.basic() + ); + From 397abc65da5ea69e8b997b60e9d939e7f0b0d028 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sat, 21 Jun 2025 02:01:56 +0900 Subject: [PATCH 16/26] fix boundary of optimize random tick --- .../main/java/org/dreeam/leaf/world/RandomTickSystem.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java index fdcaad27..23967287 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java @@ -85,7 +85,7 @@ public final class RandomTickSystem { if (chunk4 != null) tickBlock(world, chunk4, random); } for (k = queue.size(); j < k; j++) { - LevelChunk chunk = getChunk(world, queueRaw[j]); + final LevelChunk chunk = getChunk(world, queueRaw[j]); if (chunk != null) tickBlock(world, chunk, random); } @@ -100,7 +100,11 @@ public final class RandomTickSystem { } private static void tickBlock(ServerLevel world, LevelChunk chunk, RandomSource random) { - OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(chunk.leaf$tickingBlocksCount())); + int count = chunk.leaf$tickingBlocksCount(); + if (count == 0) { + return; + } + OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(count)); if (optionalPos.isEmpty()) { return; } From 5311ae81c6ca989fdaaf38f6eddfcc0308d3c8ac Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sat, 21 Jun 2025 02:01:56 +0900 Subject: [PATCH 17/26] fix boundary of optimize random tick --- .../main/java/org/dreeam/leaf/world/RandomTickSystem.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java index fdcaad27..23967287 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java @@ -85,7 +85,7 @@ public final class RandomTickSystem { if (chunk4 != null) tickBlock(world, chunk4, random); } for (k = queue.size(); j < k; j++) { - LevelChunk chunk = getChunk(world, queueRaw[j]); + final LevelChunk chunk = getChunk(world, queueRaw[j]); if (chunk != null) tickBlock(world, chunk, random); } @@ -100,7 +100,11 @@ public final class RandomTickSystem { } private static void tickBlock(ServerLevel world, LevelChunk chunk, RandomSource random) { - OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(chunk.leaf$tickingBlocksCount())); + int count = chunk.leaf$tickingBlocksCount(); + if (count == 0) { + return; + } + OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(count)); if (optionalPos.isEmpty()) { return; } From 6a52966a753f38f1d2e56eb7acfa63ff55f26c21 Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sat, 21 Jun 2025 04:08:40 +0800 Subject: [PATCH 18/26] Backport DC's 1.21.6 update --- ...7-Paper-Rewrite-dataconverter-system.patch | 236 ++++++++++++++---- 1 file changed, 189 insertions(+), 47 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0277-Paper-Rewrite-dataconverter-system.patch b/leaf-server/minecraft-patches/features/0277-Paper-Rewrite-dataconverter-system.patch index bd0c9a98..f551542d 100644 --- a/leaf-server/minecraft-patches/features/0277-Paper-Rewrite-dataconverter-system.patch +++ b/leaf-server/minecraft-patches/features/0277-Paper-Rewrite-dataconverter-system.patch @@ -220,10 +220,10 @@ index 0000000000000000000000000000000000000000..515f6691c72ffa82ac8b92646768be7a +} diff --git a/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java b/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java new file mode 100644 -index 0000000000000000000000000000000000000000..427222ee6d4300757864ebd1158f86443252604e +index 0000000000000000000000000000000000000000..d8662b811b47787f12ebf53e410dc4fa7fad0e10 --- /dev/null +++ b/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java -@@ -0,0 +1,485 @@ +@@ -0,0 +1,487 @@ +package ca.spottedleaf.dataconverter.minecraft; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -504,9 +504,9 @@ index 0000000000000000000000000000000000000000..427222ee6d4300757864ebd1158f8644 + 4311, + 4312, + 4314, -+// 4420, -+// 4424, -+ // All up to 1.21.6-pre2 ++ //4420, ++ //4424, ++ // All up to 1.21.6 + }; + Arrays.sort(converterVersions); + @@ -533,6 +533,8 @@ index 0000000000000000000000000000000000000000..427222ee6d4300757864ebd1158f8644 + registerSubVersion(MCVersions.V24W07A + 1, 5); + registerSubVersion(MCVersions.V24W07A + 1, 6); + ++ registerSubVersion(V4290.VERSION, 1); ++ + // register breakpoints here + // for all major releases after 1.16, add them. this reduces the work required to determine if a breakpoint + // is needed for new converters @@ -559,7 +561,7 @@ index 0000000000000000000000000000000000000000..427222ee6d4300757864ebd1158f8644 + + // There is a read of entity sub data in V4299 (salmon) which was written to after V1_20_6 + // There is also a sub type read in V4290 as it reads and converts all data within a text component -+ registerBreakpointBefore(V4290.VERSION); ++ registerBreakpointAfter(V4290.VERSION); + } + + static { @@ -711,10 +713,10 @@ index 0000000000000000000000000000000000000000..427222ee6d4300757864ebd1158f8644 +} diff --git a/ca/spottedleaf/dataconverter/minecraft/MCVersions.java b/ca/spottedleaf/dataconverter/minecraft/MCVersions.java new file mode 100644 -index 0000000000000000000000000000000000000000..d2d572733f848108c156a629c9e65d35e0c681c4 +index 0000000000000000000000000000000000000000..f54d93488ce8d6161bc69735fe4be9c54c374424 --- /dev/null +++ b/ca/spottedleaf/dataconverter/minecraft/MCVersions.java -@@ -0,0 +1,593 @@ +@@ -0,0 +1,599 @@ +package ca.spottedleaf.dataconverter.minecraft; + +@SuppressWarnings("unused") @@ -1296,15 +1298,21 @@ index 0000000000000000000000000000000000000000..d2d572733f848108c156a629c9e65d35 + public static final int V1_21_5_RC1 = 4323; + public static final int V1_21_5_RC2 = 4324; + public static final int V1_21_5 = 4325; -+// public static final int V25W15A = 4422; -+// public static final int V25W16A = 4423; -+// public static final int V25W17A = 4425; -+// public static final int V25W18A = 4426; -+// public static final int V25W19A = 4427; -+// public static final int V25W20A = 4428; -+// public static final int V25W21A = 4429; -+// public static final int V1_21_6_PRE1 = 4430; -+// public static final int V1_21_6_PRE2 = 4431; ++ /* ++ public static final int V25W15A = 4422; ++ public static final int V25W16A = 4423; ++ public static final int V25W17A = 4425; ++ public static final int V25W18A = 4426; ++ public static final int V25W19A = 4427; ++ public static final int V25W20A = 4428; ++ public static final int V25W21A = 4429; ++ public static final int V1_21_6_PRE1 = 4430; ++ public static final int V1_21_6_PRE2 = 4431; ++ public static final int V1_21_6_PRE3 = 4432; ++ public static final int V1_21_6_PRE4 = 4433; ++ public static final int V1_21_6_RC1 = 4434; ++ public static final int V1_21_6 = 4435; ++ */ + + private MCVersions() {} +} @@ -9282,10 +9290,10 @@ index 0000000000000000000000000000000000000000..e1f7c0d7fd80556941bbba8018aa85e7 +} diff --git a/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java b/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java new file mode 100644 -index 0000000000000000000000000000000000000000..1a09db070633d257174b6985d70f1801b06492d5 +index 0000000000000000000000000000000000000000..edeb0db8e00157da02f9318a1625a62a06f7de0e --- /dev/null +++ b/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java -@@ -0,0 +1,367 @@ +@@ -0,0 +1,369 @@ +package ca.spottedleaf.dataconverter.minecraft.datatypes; + +import ca.spottedleaf.dataconverter.minecraft.versions.*; @@ -9646,9 +9654,11 @@ index 0000000000000000000000000000000000000000..1a09db070633d257174b6985d70f1801 + V4311.register(); + V4312.register(); + V4314.register(); -+// V4420.register(); -+// V4421.register(); -+// V4424.register(); ++ /* ++ V4420.register(); ++ V4421.register(); ++ V4424.register(); ++ */ + } + + private MCTypeRegistry() {} @@ -9898,6 +9908,90 @@ index 0000000000000000000000000000000000000000..17ded002b5546de8be4a5238c20ccfda + + private ComponentUtils() {} +} +diff --git a/ca/spottedleaf/dataconverter/minecraft/util/StringWalker.java b/ca/spottedleaf/dataconverter/minecraft/util/StringWalker.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4e1add641c092b241b48e93732dab4ef646eafc3 +--- /dev/null ++++ b/ca/spottedleaf/dataconverter/minecraft/util/StringWalker.java +@@ -0,0 +1,78 @@ ++package ca.spottedleaf.dataconverter.minecraft.util; ++ ++public final class StringWalker { ++ ++ public final String string; ++ private int index; // index of next value to return ++ private final int maxIndex; // exclusive ++ ++ public StringWalker(final String string) { ++ this(string, 0); ++ } ++ ++ public StringWalker(final String string, final int index) { ++ this(string, index, string.length()); ++ } ++ ++ public StringWalker(final String string, final int index, final int maxIndex) { ++ this.string = string; ++ this.index = index; ++ this.maxIndex = maxIndex; ++ ++ if (maxIndex < 0 || maxIndex > string.length()) { ++ throw new IllegalArgumentException("Max index out of string range"); ++ } ++ ++ if (index < 0 || index > maxIndex) { ++ throw new IllegalArgumentException("Index out of string range"); ++ } ++ } ++ ++ public int getIndex() { ++ return this.index; ++ } ++ ++ public void setIndex(final int to) { ++ this.index = to; ++ } ++ ++ private void checkNext() { ++ if (!this.hasNext()) { ++ throw this.parseFail(this.getIndex(), "Expecting more input"); ++ } ++ } ++ ++ public boolean hasNext() { ++ return this.index < this.maxIndex; ++ } ++ ++ public char next() { ++ return this.string.charAt(this.index++); ++ } ++ ++ public char peek() { ++ return this.string.charAt(this.index); ++ } ++ ++ public void advance() { ++ ++this.index; ++ } ++ ++ public void skipWhitespace() { ++ while (this.hasNext() || Character.isWhitespace(this.peek())) { ++ this.advance(); ++ } ++ } ++ ++ public boolean skipIf(final char c) { ++ if (this.hasNext() && this.peek() == c) { ++ this.advance(); ++ return true; ++ } ++ return false; ++ } ++ ++ public IllegalStateException parseFail(final int index, final String reason) { ++ return new IllegalStateException("At column " + index + ": " + reason); ++ } ++} diff --git a/ca/spottedleaf/dataconverter/minecraft/util/Version.java b/ca/spottedleaf/dataconverter/minecraft/util/Version.java new file mode 100644 index 0000000000000000000000000000000000000000..57563e3f85653d1e946495e7609c6ee644095ceb @@ -24764,15 +24858,13 @@ index 0000000000000000000000000000000000000000..7d09c4218d0db8119d1681bf95900be8 +} diff --git a/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java b/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java new file mode 100644 -index 0000000000000000000000000000000000000000..4197a5e89aec77f2893f0f118a927b96d5377ec1 +index 0000000000000000000000000000000000000000..d5dfa9a64e2d3f9a37a5bdde60b92ed93bd89aed --- /dev/null +++ b/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java -@@ -0,0 +1,248 @@ +@@ -0,0 +1,312 @@ +package ca.spottedleaf.dataconverter.minecraft.versions; + +import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+import ca.spottedleaf.dataconverter.minecraft.MCDataConverter; +import ca.spottedleaf.dataconverter.minecraft.MCVersions; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; +import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; @@ -24912,6 +25004,70 @@ index 0000000000000000000000000000000000000000..4197a5e89aec77f2893f0f118a927b96 + } + } + ++ private static void directWalkComponentList(final ListType list, final long fromVersion, final long toVersion) { ++ for (int i = 0, len = list.size(); i < len; ++i) { ++ directWalkComponent(list.getGeneric(i), fromVersion, toVersion); ++ } ++ } ++ ++ private static void directWalkComponent(final Object input, final long fromVersion, final long toVersion) { ++ if (input instanceof ListType listType) { ++ directWalkComponentList(listType, fromVersion, toVersion); ++ } else if (input instanceof MapType root) { ++ final ListType extra = root.getListUnchecked("extra"); ++ if (extra != null) { ++ directWalkComponentList(extra, fromVersion, toVersion); ++ } ++ ++ final Object separator = root.getGeneric("separator"); ++ if (separator != null) { ++ directWalkComponent(separator, fromVersion, toVersion); ++ } ++ ++ final MapType clickEvent = root.getMap("clickEvent"); ++ if (clickEvent != null) { ++ switch (clickEvent.getString("action", "")) { ++ case "run_command": ++ case "suggest_command": { ++ WalkerUtils.convert(MCTypeRegistry.DATACONVERTER_CUSTOM_TYPE_COMMAND, clickEvent, "value", fromVersion, toVersion); ++ break; ++ } ++ } ++ } ++ ++ final MapType hoverEvent = root.getMap("hoverEvent"); ++ if (hoverEvent != null) { ++ switch (hoverEvent.getString("action", "")) { ++ case "show_text": { ++ final Object contents = hoverEvent.getGeneric("contents"); ++ if (contents != null) { ++ directWalkComponent(contents, fromVersion, toVersion); ++ } ++ break; ++ } ++ case "show_item": { ++ if (hoverEvent.hasKey("contents", ObjectType.STRING)) { ++ WalkerUtils.convert(MCTypeRegistry.ITEM_NAME, hoverEvent, "contents", fromVersion, toVersion); ++ } else { ++ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, hoverEvent, "contents", fromVersion, toVersion); ++ } ++ break; ++ } ++ case "show_entity": { ++ WalkerUtils.convert(MCTypeRegistry.ENTITY_NAME, hoverEvent, "type", fromVersion, toVersion); ++ ++ final Object name = hoverEvent.getGeneric("name"); ++ if (name != null) { ++ directWalkComponent(name, fromVersion, toVersion); ++ } ++ break; ++ } ++ // default: do nothing ++ } ++ } ++ } // else: should only be string ++ } ++ + public static void register() { + MCTypeRegistry.TEXT_COMPONENT.addStructureConverter(new DataConverter<>(VERSION) { + @Override @@ -24958,6 +25114,7 @@ index 0000000000000000000000000000000000000000..4197a5e89aec77f2893f0f118a927b96 + }; + + convertNested(ret); ++ directWalkComponent(ret, sourceVersion, toVersion); + return ret; + } + } catch (final JsonParseException ex) { @@ -24968,7 +25125,8 @@ index 0000000000000000000000000000000000000000..4197a5e89aec77f2893f0f118a927b96 + } + }); + -+ MCTypeRegistry.TEXT_COMPONENT.addStructureWalker(VERSION, (final Object input, final long fromVersion, final long toVersion) -> { ++ // step 1 ++ MCTypeRegistry.TEXT_COMPONENT.addStructureWalker(VERSION, 1, (final Object input, final long fromVersion, final long toVersion) -> { + if (input instanceof ListType listType) { + WalkerUtils.convert(MCTypeRegistry.TEXT_COMPONENT, listType, fromVersion, toVersion); + } else if (input instanceof MapType root) { @@ -30277,10 +30435,10 @@ index 0000000000000000000000000000000000000000..6704da4a40522a4f40cd770a4cbaaa8e +} diff --git a/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java b/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java new file mode 100644 -index 0000000000000000000000000000000000000000..d96808060623f73b08dec8eb6d6fdfca4d309d16 +index 0000000000000000000000000000000000000000..3ace24bdd5e5da4333e25c9c681007e6a85d52ab --- /dev/null +++ b/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java -@@ -0,0 +1,189 @@ +@@ -0,0 +1,181 @@ +package ca.spottedleaf.dataconverter.types.json; + +import ca.spottedleaf.dataconverter.minecraft.converters.helpers.CopyHelper; @@ -30461,14 +30619,6 @@ index 0000000000000000000000000000000000000000..d96808060623f73b08dec8eb6d6fdfca + + return ret; + } -+ -+ private static MapType convertJson(final TypeUtil to, final JsonMapType json) { -+ return convertJson(to, json.map, json.compressed); -+ } -+ -+ private static ListType convertJson(final TypeUtil to, final JsonListType json) { -+ return convertJson(to, json.array, json.compressed); -+ } +} diff --git a/ca/spottedleaf/dataconverter/types/nbt/NBTListType.java b/ca/spottedleaf/dataconverter/types/nbt/NBTListType.java new file mode 100644 @@ -31508,10 +31658,10 @@ index 0000000000000000000000000000000000000000..2558d9014e1daff6dd4a44ad85bbc025 +} diff --git a/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java b/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java new file mode 100644 -index 0000000000000000000000000000000000000000..32d90fc5ab415b0261af8377b130404ad37e19ee +index 0000000000000000000000000000000000000000..61e98240a221a75780e311c0777a8c43c4297d65 --- /dev/null +++ b/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java -@@ -0,0 +1,136 @@ +@@ -0,0 +1,128 @@ +package ca.spottedleaf.dataconverter.types.nbt; + +import ca.spottedleaf.dataconverter.minecraft.converters.helpers.CopyHelper; @@ -31639,14 +31789,6 @@ index 0000000000000000000000000000000000000000..32d90fc5ab415b0261af8377b130404a + + return ret; + } -+ -+ public static MapType convertNBT(final TypeUtil to, final NBTMapType nbt) { -+ return convertNBT(to, nbt.map); -+ } -+ -+ public static ListType convertNBT(final TypeUtil to, final NBTListType nbt) { -+ return convertNBT(to, nbt.list); -+ } +} diff --git a/ca/spottedleaf/dataconverter/util/Int2IntArraySortedMap.java b/ca/spottedleaf/dataconverter/util/Int2IntArraySortedMap.java new file mode 100644 From 7973f6b3b60b3fbad9b4d9de650efed764fa6214 Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sat, 21 Jun 2025 10:12:47 +0800 Subject: [PATCH 19/26] Update changes from ver/1.21.4 branch --- .../world/block/OptimizedPoweredRails.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java b/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java index f4f3c7be..7e34b2e1 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/world/block/OptimizedPoweredRails.java @@ -20,8 +20,6 @@ public class OptimizedPoweredRails { private static final int UPDATE_FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS; - private static int RAIL_POWER_LIMIT = 8; - private static final Object2BooleanOpenHashMap CHECKED_POS_POOL = new Object2BooleanOpenHashMap<>(); private static void giveShapeUpdate(Level level, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) { @@ -36,14 +34,6 @@ public class OptimizedPoweredRails { ); } - public static int getRailPowerLimit() { - return RAIL_POWER_LIMIT; - } - - public static void setRailPowerLimit(int powerLimit) { - RAIL_POWER_LIMIT = powerLimit; - } - public static void updateState(PoweredRailBlock self, BlockState state, Level level, BlockPos pos) { boolean shouldBePowered = level.hasNeighborSignal(pos) || findPoweredRailSignalFaster(self, level, pos, state, true, 0, CHECKED_POS_POOL) || @@ -97,7 +87,7 @@ public class OptimizedPoweredRails { private static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level level, BlockPos pos, BlockState state, boolean searchForward, int distance, Object2BooleanOpenHashMap checkedPos) { - if (distance >= RAIL_POWER_LIMIT - 1) return false; + if (distance >= level.purpurConfig.railActivationRange) return false; int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); @@ -203,7 +193,8 @@ public class OptimizedPoweredRails { private static void setRailPositionsPower(PoweredRailBlock self, Level level, BlockPos pos, Object2BooleanOpenHashMap checkedPos, int[] count, int i, Direction dir) { - for (int z = 1; z < RAIL_POWER_LIMIT; z++) { + final int railPowerLimit = level.purpurConfig.railActivationRange; + for (int z = 1; z < railPowerLimit; z++) { BlockPos newPos = pos.relative(dir, z); BlockState state = level.getBlockState(newPos); if (checkedPos.containsKey(newPos)) { @@ -229,7 +220,8 @@ public class OptimizedPoweredRails { int[] count, int i, Direction dir) { Object2BooleanOpenHashMap checkedPos = CHECKED_POS_POOL; checkedPos.clear(); - for (int z = 1; z < RAIL_POWER_LIMIT; z++) { + final int railPowerLimit = level.purpurConfig.railActivationRange; + for (int z = 1; z < railPowerLimit; z++) { BlockPos newPos = pos.relative(dir, z); BlockState state = level.getBlockState(newPos); if (!state.is(self) || !state.getValue(POWERED) || level.hasNeighborSignal(newPos) || From 5ef030ab1e2c223e6a0aad8e79e1b94b7137f84d Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sat, 21 Jun 2025 11:04:38 +0800 Subject: [PATCH 20/26] [ci skip] Updated Upstream (Paper/Purpur) Upstream has released updates that appear to apply and compile correctly Paper Changes: PaperMC/Paper@39203a65 [ci/skip] Publish PR API and dev bundles (#12672) PaperMC/Paper@a1b30587 Provide env environment variable and copy spigots sys prop for overriding default repository Purpur Changes: PurpurMC/Purpur@b1d412fb Updated Upstream (Paper) PurpurMC/Purpur@293e28a0 use empty registryaccess where context is not needed, closes #1676 PurpurMC/Purpur@452bb319 port PaperMC/Paper#12654, closes #1665 PurpurMC/Purpur@849bc79c register test subcommands used for debugging, closes #1675 PurpurMC/Purpur@61d7f559 Updated Upstream (Paper) --- gradle.properties | 2 +- leaf-api/build.gradle.kts.patch | 6 +++-- ...0007-Do-not-log-plugin-library-loads.patch | 8 +++--- .../features/0013-Purpur-API-Changes.patch | 2 +- ...nfigurable-LibraryLoader-maven-repos.patch | 6 ++--- ...0098-Purpur-Server-Minecraft-Changes.patch | 26 +++++++++++++++---- ...invalid-flatten-text-component-parse.patch | 4 +-- .../0009-Purpur-Server-Paper-Changes.patch | 2 +- scripts/upstreamCommit.sh | 4 +-- 9 files changed, 39 insertions(+), 21 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1572853e..967b6a66 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group=cn.dreeam.leaf mcVersion=1.21.5 version=1.21.5-R0.1-SNAPSHOT -paperCommit=ba7fb23ddd2376079951d1e22f9204d1ed691585 +paperCommit=a1b30587d9d5a5d9bf1530f7d1e289f2e29991b6 org.gradle.configuration-cache=true org.gradle.caching=true diff --git a/leaf-api/build.gradle.kts.patch b/leaf-api/build.gradle.kts.patch index 9dd03e4e..53d109c7 100644 --- a/leaf-api/build.gradle.kts.patch +++ b/leaf-api/build.gradle.kts.patch @@ -145,11 +145,13 @@ "https://javadoc.io/doc/org.jetbrains/annotations/$annotationsVersion/", "https://javadoc.io/doc/org.joml/joml/1.10.8/", "https://www.javadoc.io/doc/com.google.code.gson/gson/2.11.0", -@@ -185,7 +_,7 @@ +@@ -184,8 +_,8 @@ + "https://jd.advntr.dev/text-serializer-plain/$adventureVersion/", "https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/", "https://javadoc.io/doc/org.slf4j/slf4j-api/$slf4jVersion/", - "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", +- // "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", // TODO: Broken - "https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3", ++ "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", + "https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.9.22", // Leaf - Bump Dependencies ) options.tags("apiNote:a:API Note:") diff --git a/leaf-api/paper-patches/features/0007-Do-not-log-plugin-library-loads.patch b/leaf-api/paper-patches/features/0007-Do-not-log-plugin-library-loads.patch index cef79fa0..dbe2ef00 100644 --- a/leaf-api/paper-patches/features/0007-Do-not-log-plugin-library-loads.patch +++ b/leaf-api/paper-patches/features/0007-Do-not-log-plugin-library-loads.patch @@ -55,10 +55,10 @@ index 163e9a0e179dc88be93614ff66ee2be3eccc694f..539786355ac89b5eb8ad876e65662e84 * This class was not meant to be constructed explicitly * diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -index 3200a3c9af5fa2ecbbc2b07be3ec31a2681180a8..cfe41c0a67c8d729b6bd23b0cfa32db3c9db9f74 100644 +index 7e4e702845f61703f0741add59f7cfc0afea1543..23e3fcc8c2d6e0555448295199eee186de619042 100644 --- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -@@ -63,6 +63,7 @@ public class LibraryLoader { +@@ -77,6 +77,7 @@ public class LibraryLoader { session.setTransferListener(new AbstractTransferListener() { @Override public void transferStarted(@NotNull TransferEvent event) { @@ -66,7 +66,7 @@ index 3200a3c9af5fa2ecbbc2b07be3ec31a2681180a8..cfe41c0a67c8d729b6bd23b0cfa32db3 logger.log(Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName()); } }); -@@ -88,6 +89,7 @@ public class LibraryLoader { +@@ -102,6 +103,7 @@ public class LibraryLoader { // Paper end - plugin loader api return null; } @@ -74,7 +74,7 @@ index 3200a3c9af5fa2ecbbc2b07be3ec31a2681180a8..cfe41c0a67c8d729b6bd23b0cfa32db3 logger.log(Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[] { java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix -@@ -140,6 +142,7 @@ public class LibraryLoader { +@@ -154,6 +156,7 @@ public class LibraryLoader { } jarFiles.add(url); diff --git a/leaf-api/paper-patches/features/0013-Purpur-API-Changes.patch b/leaf-api/paper-patches/features/0013-Purpur-API-Changes.patch index e9f0a5fa..87eb0b2f 100644 --- a/leaf-api/paper-patches/features/0013-Purpur-API-Changes.patch +++ b/leaf-api/paper-patches/features/0013-Purpur-API-Changes.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Purpur API Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur -Commit: aa289e2c6ff801551fb2f585269ccffed3a154fa +Commit: 61d7f5590e79909caba55e9f00cefdd51006d015 Patches listed below are removed in this patch, They exists in Gale or Leaf: * "co/aikar/timings/TimedEventExecutor.java.patch" diff --git a/leaf-api/paper-patches/features/0017-Configurable-LibraryLoader-maven-repos.patch b/leaf-api/paper-patches/features/0017-Configurable-LibraryLoader-maven-repos.patch index 3e78fd90..6a479722 100644 --- a/leaf-api/paper-patches/features/0017-Configurable-LibraryLoader-maven-repos.patch +++ b/leaf-api/paper-patches/features/0017-Configurable-LibraryLoader-maven-repos.patch @@ -22,14 +22,14 @@ index 107705db2d82b7c191e5e625ec888e0bc3b03831..77a58fc7c173b1724d44b0eeaf23b4a1 /** diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -index cfe41c0a67c8d729b6bd23b0cfa32db3c9db9f74..9f167a9cb4a93a79b8ed709b61214ce0138a875d 100644 +index 23e3fcc8c2d6e0555448295199eee186de619042..502c51b3ae0a05569540c09b4c51dad1438da36e 100644 --- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -@@ -74,7 +74,19 @@ public class LibraryLoader { +@@ -88,7 +88,19 @@ public class LibraryLoader { session.setSystemProperties(System.getProperties()); session.setReadOnly(); -- this.repositories = repository.newResolutionRepositories(session, Arrays.asList(new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2").build())); +- this.repositories = repository.newResolutionRepositories(session, getRepositories()); + // Leaf start - Configurable LibraryLoader maven repos + this.repositories = repository.newResolutionRepositories( + session, diff --git a/leaf-server/minecraft-patches/features/0098-Purpur-Server-Minecraft-Changes.patch b/leaf-server/minecraft-patches/features/0098-Purpur-Server-Minecraft-Changes.patch index a7711fb1..4b458780 100644 --- a/leaf-server/minecraft-patches/features/0098-Purpur-Server-Minecraft-Changes.patch +++ b/leaf-server/minecraft-patches/features/0098-Purpur-Server-Minecraft-Changes.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Purpur Server Minecraft Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur -Commit: aa289e2c6ff801551fb2f585269ccffed3a154fa +Commit: 61d7f5590e79909caba55e9f00cefdd51006d015 Patches listed below are removed in this patch, They exists in Gale or Leaf: * "net/minecraft/CrashReport.java.patch" @@ -38,6 +38,8 @@ Patches listed below are removed in this patch, They exists in Gale or Leaf: - MC-238526 - Fix spawner not spawning water animals correctly * "net/minecraft/world/entity/projectile/AbstractArrow.java.patch" - Arrows should not reset despawn counter +* "net/minecraft/world/inventory/AbstractContainerMenu.java.patch" + - PaperPR#12654 * "net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch" - Rebrand @@ -264,6 +266,19 @@ index fafbc8a9229432c4fb290a54cf453cd0c0c7b3b6..b0a86aac9603e72062f59dbe67c88ed8 @Override public boolean isClientAuthoritative() { return false; +diff --git a/net/minecraft/gametest/framework/TestCommand.java b/net/minecraft/gametest/framework/TestCommand.java +index 1709f81a3d5fba97ca0e0a5ce9774bf151d7cb7d..5c2b36b316c5c1ec2332551ac134b9ab67f2f223 100644 +--- a/net/minecraft/gametest/framework/TestCommand.java ++++ b/net/minecraft/gametest/framework/TestCommand.java +@@ -455,7 +455,7 @@ public class TestCommand { + ) + ) + ); +- if (SharedConstants.IS_RUNNING_IN_IDE) { ++ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur - register minecraft debug commands + literalArgumentBuilder = literalArgumentBuilder.then( + Commands.literal("export") + .then( diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java index 4ed9611994c5c8da01fede690197527c5b3a5731..00a82873d226f113278632a53c0faca420dd67d4 100644 --- a/net/minecraft/network/Connection.java @@ -21810,14 +21825,15 @@ index 0000000000000000000000000000000000000000..922e48799c43ca322a8f550c98a26e1e +} diff --git a/org/purpurmc/purpur/entity/PurpurStoredBee.java b/org/purpurmc/purpur/entity/PurpurStoredBee.java new file mode 100644 -index 0000000000000000000000000000000000000000..1cd79edbe87d9109bc132e64f6840981aaaab110 +index 0000000000000000000000000000000000000000..800cc8b2204c0ef885ff65005f6850749aaf445b --- /dev/null +++ b/org/purpurmc/purpur/entity/PurpurStoredBee.java -@@ -0,0 +1,104 @@ +@@ -0,0 +1,105 @@ +package org.purpurmc.purpur.entity; + +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.text.Component; ++import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; @@ -21847,7 +21863,7 @@ index 0000000000000000000000000000000000000000..1cd79edbe87d9109bc132e64f6840981 + this.blockStorage = blockStorage; + + CompoundTag customData = handle.occupant.entityData().copyTag(); -+ net.minecraft.network.chat.Component customNameMinecraft = BlockEntity.parseCustomNameSafe(customData.get("CustomName"), ((CraftWorld) blockStorage.getWorld()).getHandle().registryAccess()); ++ net.minecraft.network.chat.Component customNameMinecraft = BlockEntity.parseCustomNameSafe(customData.get("CustomName"), RegistryAccess.EMPTY); + this.customName = customNameMinecraft == null ? null : PaperAdventure.asAdventure(customNameMinecraft); + + if (customData.get("BukkitValues") instanceof CompoundTag compoundTag) { @@ -21914,7 +21930,7 @@ index 0000000000000000000000000000000000000000..1cd79edbe87d9109bc132e64f6840981 + if(customName == null) { + handle.occupant.entityData().copyTag().remove("CustomName"); + } else { -+ handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), ((CraftWorld) blockStorage.getWorld()).getHandle().registryAccess())); ++ handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), RegistryAccess.EMPTY)); + } + } +} diff --git a/leaf-server/minecraft-patches/features/0278-do-not-log-invalid-flatten-text-component-parse.patch b/leaf-server/minecraft-patches/features/0278-do-not-log-invalid-flatten-text-component-parse.patch index 8d9554b7..68eecd26 100644 --- a/leaf-server/minecraft-patches/features/0278-do-not-log-invalid-flatten-text-component-parse.patch +++ b/leaf-server/minecraft-patches/features/0278-do-not-log-invalid-flatten-text-component-parse.patch @@ -5,10 +5,10 @@ Subject: [PATCH] do not log invalid flatten text component parse diff --git a/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java b/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java -index 4197a5e89aec77f2893f0f118a927b96d5377ec1..de99a05bbe3e8dac2d6307eb53d954d77904a0c4 100644 +index d5dfa9a64e2d3f9a37a5bdde60b92ed93bd89aed..83155bf0befab0207a4b756b19527d071037a870 100644 --- a/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java +++ b/ca/spottedleaf/dataconverter/minecraft/versions/V4290.java -@@ -191,7 +191,7 @@ public final class V4290 { +@@ -254,7 +254,7 @@ public final class V4290 { return ret; } } catch (final JsonParseException ex) { diff --git a/leaf-server/paper-patches/features/0009-Purpur-Server-Paper-Changes.patch b/leaf-server/paper-patches/features/0009-Purpur-Server-Paper-Changes.patch index 024062a6..2749dc77 100644 --- a/leaf-server/paper-patches/features/0009-Purpur-Server-Paper-Changes.patch +++ b/leaf-server/paper-patches/features/0009-Purpur-Server-Paper-Changes.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Purpur Server Paper Changes Original license: MIT Original project: https://github.com/PurpurMC/Purpur -Commit: aa289e2c6ff801551fb2f585269ccffed3a154fa +Commit: 61d7f5590e79909caba55e9f00cefdd51006d015 Patches listed below are removed in this patch, They exists in Gale or Leaf: * "Rebrand.patch" diff --git a/scripts/upstreamCommit.sh b/scripts/upstreamCommit.sh index 4fd006df..43e196b3 100755 --- a/scripts/upstreamCommit.sh +++ b/scripts/upstreamCommit.sh @@ -53,7 +53,7 @@ logsuffix="" # Paper updates if [ -n "$paperHash" ]; then newHash=$(git diff gradle.properties | awk '/^+paperCommit =/{print $NF}') - paper=$(getCommits "PaperMC/Paper" "$paperHash" $(echo $newHash | grep . -q && echo $newHash || echo "HEAD")) + paper=$(getCommits "PaperMC/Paper" "$paperHash" $(echo $newHash | grep . -q && echo $newHash || echo "ver/1.21.5")) # Update this on every version update # Updates found if [ -n "$paper" ]; then @@ -64,7 +64,7 @@ fi # Purpur updates if [ -n "$purpurHash" ]; then - purpur=$(getCommits "PurpurMC/Purpur" "$purpurHash" "HEAD") + purpur=$(getCommits "PurpurMC/Purpur" "$purpurHash" "ver/1.21.5") # Update this on every version update # Updates found if [ -n "$purpur" ]; then From cb21caa1c2d10a733e7fe48f7a01676efd6774de Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sun, 22 Jun 2025 01:50:49 +0900 Subject: [PATCH 21/26] readd some fixes in async target finding --- .../features/0238-Async-target-finding.patch | 165 ++++++++++-------- 1 file changed, 96 insertions(+), 69 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch index 78f696e6..ad24c441 100644 --- a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch +++ b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch @@ -581,7 +581,7 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..4eec8eda6ea1698529e0392bc75c07be } else { this.parent = animal; diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01c8bb0ba8 100644 +index e82e32407cec6109b9c3b0106295217f4a3f4aa2..127609e53f566413f93b983719604858802d8a6d 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -26,13 +26,23 @@ public class GoalSelector { @@ -767,7 +767,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01 for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams wrappedGoal.stop(); -@@ -116,6 +256,18 @@ public class GoalSelector { +@@ -116,6 +256,24 @@ public class GoalSelector { } public void tickRunningGoals(boolean tickAllRunning) { @@ -779,6 +779,12 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01 + availableGoalsDirty = false; + } + ctxState = tickAllRunning ? 2 : 3; ++ } else { ++ for (WrappedGoal wrappedGoal : java.util.Objects.requireNonNull(this.ctxGoals)) { ++ if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) { ++ wrappedGoal.tick(); ++ } ++ } + } + return; + } @@ -787,7 +793,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..0998aa502b5a361558f1812bf93c2e01 if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) { wrappedGoal.tick(); diff --git a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index be59d0c27a83b329ec3f97c029cfb9c114e22472..888fd1919954acf3ec3c5d5a115dffc2e0fd3caf 100644 +index be59d0c27a83b329ec3f97c029cfb9c114e22472..83a0e5ffad44a628b60a6a2cc136559b0a0377f3 100644 --- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java +++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java @@ -20,20 +20,83 @@ public class LlamaFollowCaravanGoal extends Goal { @@ -852,7 +858,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..888fd1919954acf3ec3c5d5a115dffc2 + // Leaf start - Async target finding + Llama llama = poll(); + double d = Double.MAX_VALUE; -+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { ++ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (llama == null) { + findTargetAsync(); + return false; @@ -997,10 +1003,10 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..126bd98bc5980a2f1177bd7c74918b86 @Override public boolean canContinueToUse() { diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad51691a42 100644 +index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..89851bac25a4a1d3c499ba379bdadd357e079ea8 100644 --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -@@ -41,8 +41,60 @@ public abstract class MoveToBlockGoal extends Goal { +@@ -41,14 +41,73 @@ public abstract class MoveToBlockGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP)); } @@ -1017,10 +1023,15 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad + return true; + } + -+ protected void getBlockAsync() { ++ protected boolean findNearestBlockAsync() { ++ // Leaf start - Async target finding ++ if (!org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) { ++ return findNearestBlock(); ++ } ++ // Leaf end - Async target finding + final var mob = this.mob; + final var ctx = mob.getGoalCtx(); -+ if (!ctx.state) return; ++ if (!ctx.state) return false; + final var serverLevel = getServerLevel(mob); + final TypeToCheck ty = this.typeToCheck(); + final net.minecraft.world.level.block.Block toRemove; @@ -1036,6 +1047,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad + final float restrictRadius = mob.getRestrictRadius(); + final BlockPos restrictCenter = mob.getRestrictCenter(); + ctx.wake = () -> findNearestBlockAsync(ty, toRemove, mob, serverLevel, verticalSearchStart, searchRange, verticalSearchRange, blockPos, restrictRadius, restrictCenter); ++ return false; + } + + protected enum TypeToCheck { @@ -1048,6 +1060,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad + Strider, + TurtleToWater, + TurtleLay, ++ Unknown, + } + // Leaf end - Async target finding + @@ -1061,20 +1074,14 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad if (this.nextStartTick > 0) { this.nextStartTick--; return false; -@@ -109,6 +161,12 @@ public abstract class MoveToBlockGoal extends Goal { + } else { + this.nextStartTick = this.nextStartTick(this.mob); +- return this.findNearestBlock(); ++ return this.findNearestBlockAsync(); // Leaf - Async target finding + } } - protected boolean findNearestBlock() { -+ // Leaf start - Async target finding -+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) { -+ getBlockAsync(); -+ return false; -+ } -+ // Leaf end - Async target finding - int i = this.searchRange; - int i1 = this.verticalSearchRange; - BlockPos blockPos = this.mob.blockPosition(); -@@ -133,5 +191,105 @@ public abstract class MoveToBlockGoal extends Goal { +@@ -133,5 +192,108 @@ public abstract class MoveToBlockGoal extends Goal { return false; } @@ -1117,7 +1124,9 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad protected abstract boolean isValidTarget(LevelReader level, BlockPos pos); + + // Leaf start - Async target finding -+ protected abstract TypeToCheck typeToCheck(); ++ protected TypeToCheck typeToCheck() { ++ return TypeToCheck.Unknown; ++ } + + private static boolean isValidTargetAsync( + TypeToCheck type, @@ -1175,6 +1184,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..efd999c235271ac6b0935933db939cad + case TurtleLay -> { + return level.isEmptyBlock(pos.above()) && net.minecraft.world.level.block.TurtleEggBlock.isSand(level, pos); + } ++ case Unknown -> throw new IllegalStateException(); + case null -> throw new IllegalStateException(); + } + // Leaf end - Async target finding @@ -1244,10 +1254,10 @@ index 4ba5f7da27f7f6842790c0093bc0f25e138fa982..d0e3e030bc5eacc304c523afcabd193e public boolean canContinueToUse() { return this.tick > 0; diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 16ec032d84f128fc44a836843fafef303f52b699..4fe7961d031af0b2aa6b79d9f104ceb883edf301 100644 +index 16ec032d84f128fc44a836843fafef303f52b699..e3bb4c5850e25405a243aaf57e2e8b1c64381d1d 100644 --- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -@@ -37,7 +37,14 @@ public class RemoveBlockGoal extends MoveToBlockGoal { +@@ -37,10 +37,17 @@ public class RemoveBlockGoal extends MoveToBlockGoal { public boolean canUse() { if (!getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING, getServerLevel(this.removerMob).purpurConfig.zombieMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected return false; @@ -1262,7 +1272,11 @@ index 16ec032d84f128fc44a836843fafef303f52b699..4fe7961d031af0b2aa6b79d9f104ceb8 + if (this.nextStartTick > 0) { this.nextStartTick--; return false; - } else if (this.findNearestBlock()) { +- } else if (this.findNearestBlock()) { ++ } else if (this.findNearestBlockAsync()) { // Leaf - Async target finding + this.nextStartTick = reducedTickDelay(20); + return true; + } else { @@ -151,8 +158,15 @@ public class RemoveBlockGoal extends MoveToBlockGoal { protected boolean isValidTarget(LevelReader level, BlockPos pos) { ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks @@ -1281,10 +1295,18 @@ index 16ec032d84f128fc44a836843fafef303f52b699..4fe7961d031af0b2aa6b79d9f104ceb8 + // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java -index f88f618d34fb343b31de3af1a875d6633703df71..4bbd83c702a818b48313698919dc9a85392707f6 100644 +index f88f618d34fb343b31de3af1a875d6633703df71..dc90441edfa1cdd5c5e218811b0dc595e63f4e9c 100644 --- a/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java -@@ -36,12 +36,51 @@ public class TemptGoal extends Goal { +@@ -7,6 +7,7 @@ import net.minecraft.world.entity.LivingEntity; + import net.minecraft.world.entity.PathfinderMob; + import net.minecraft.world.entity.ai.attributes.Attributes; + import net.minecraft.world.entity.ai.targeting.TargetingConditions; ++import net.minecraft.world.entity.animal.horse.Llama; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.item.ItemStack; + +@@ -36,14 +37,43 @@ public class TemptGoal extends Goal { this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity)); } @@ -1314,33 +1336,27 @@ index f88f618d34fb343b31de3af1a875d6633703df71..4bbd83c702a818b48313698919dc9a85 this.calmDown--; return false; } else { +- this.player = getServerLevel(this.mob) +- .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); + // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { -+ if (poll()) { -+ if (this.player != null) { -+ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this.mob, this.player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT); -+ if (event.isCancelled()) { -+ return false; -+ } -+ this.player = (event.getTarget() == null) ? null : ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); -+ } -+ if (this.player != null) { -+ return true; -+ } -+ } else { ++ if (!poll()) { + getNearestPlayerAsync(); + return false; + } ++ } else { ++ this.player = getServerLevel(this.mob) ++ .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); + } + // Leaf end - Async target finding - this.player = getServerLevel(this.mob) - .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); // CraftBukkit start + if (this.player != null) { + org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this.mob, this.player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT); diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..9054eb373de510f7949f7070cfe69ad2fe25ea3b 100644 +index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..96ccafe979c5c15e26c12f6ca98ad1e81537bdce 100644 --- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -@@ -24,8 +24,49 @@ public class DefendVillageTargetGoal extends TargetGoal { +@@ -24,13 +24,52 @@ public class DefendVillageTargetGoal extends TargetGoal { this.setFlags(EnumSet.of(Goal.Flag.TARGET)); } @@ -1349,7 +1365,6 @@ index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..9054eb373de510f7949f7070cfe69ad2 + if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); + if (serverLevel == null || !target.isAlive() || !attackTargeting.test(serverLevel, golem, target)) return false; -+ if ((target instanceof Player player && (player.isSpectator() || player.isCreative()))) return false; + this.potentialTarget = target; + return true; + } @@ -1379,26 +1394,30 @@ index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..9054eb373de510f7949f7070cfe69ad2 @Override public boolean canUse() { + // Leaf start - Async target finding -+ if (poll()) { -+ return true; -+ } + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { -+ this.findTargetAsync(); -+ return false; -+ } -+ // Leaf end - Async target finding ++ if (!poll()) { ++ this.findTargetAsync(); ++ return false; ++ } ++ } else { AABB aabb = this.golem.getBoundingBox().inflate(10.0, 8.0, 10.0); ServerLevel serverLevel = getServerLevel(this.golem); List nearbyEntities = serverLevel.getNearbyEntities(Villager.class, this.attackTargeting, this.golem, aabb); -@@ -42,7 +83,7 @@ public class DefendVillageTargetGoal extends TargetGoal { + List nearbyPlayers = serverLevel.getNearbyPlayers(this.attackTargeting, this.golem, aabb); + ++ // Async target finding - diff + for (LivingEntity livingEntity : nearbyEntities) { + Villager villager = (Villager)livingEntity; + +@@ -41,6 +80,8 @@ public class DefendVillageTargetGoal extends TargetGoal { + } } } ++ } ++ // Leaf end - Async target finding -- return this.potentialTarget != null && !(this.potentialTarget instanceof Player player1 && (player1.isSpectator() || player1.isCreative())); -+ return this.potentialTarget != null && !(this.potentialTarget instanceof Player player1 && (player1.isSpectator() || player1.isCreative())); // Leaf - Async target finding - diff on change + return this.potentialTarget != null && !(this.potentialTarget instanceof Player player1 && (player1.isSpectator() || player1.isCreative())); } - - @Override diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..412fc8e049ba3763314ec2a56dce378cb0e4cc5f 100644 --- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java @@ -1506,10 +1525,10 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..412fc8e049ba3763314ec2a56dce378c mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason } diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..7fac18f9d41030f0e9a566fd1923ea79edde32b6 100644 +index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..d44aec876818421eb8a54007e2bdabd7d354f22b 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -@@ -41,8 +41,43 @@ public class NearestAttackableTargetGoal extends TargetG +@@ -41,12 +41,52 @@ public class NearestAttackableTargetGoal extends TargetG this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector); } @@ -1522,7 +1541,12 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..7fac18f9d41030f0e9a566fd1923ea79 + return true; + } + -+ private void findTargetAsync() { ++ protected void findTargetAsync() { ++ if (!org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { ++ findTarget(); ++ return; ++ } ++ this.target = null; + final Mob mob = this.mob; + final var ctx = mob.getGoalCtx(); + if (!ctx.state) return; @@ -1553,27 +1577,24 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..7fac18f9d41030f0e9a566fd1923ea79 if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) { return false; } else { -@@ -57,6 +92,15 @@ public class NearestAttackableTargetGoal extends TargetG +- this.findTarget(); ++ this.findTargetAsync(); // Async target finding + return this.target != null; + } + } +@@ -57,6 +97,7 @@ public class NearestAttackableTargetGoal extends TargetG protected void findTarget() { ServerLevel serverLevel = getServerLevel(this.mob); -+ -+ // Leaf start - Async target finding -+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { -+ this.findTargetAsync(); -+ this.target = null; -+ return; -+ } -+ // Leaf end - Async target finding + if (this.targetType != Player.class && this.targetType != ServerPlayer.class) { this.target = serverLevel.getNearestEntity( this.mob.level().getEntitiesOfClass(this.targetType, this.getTargetSearchArea(this.getFollowDistance()), entity -> true), diff --git a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java -index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..7274dfb52ca4a08cdebcd04294cedc73460593e5 100644 +index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..84c7b89e7c894c0f544cf0ffcf9dff3f6a5919cc 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java -@@ -23,7 +23,15 @@ public class NearestHealableRaiderTargetGoal extends Nea +@@ -23,12 +23,20 @@ public class NearestHealableRaiderTargetGoal extends Nea @Override public boolean canUse() { @@ -1590,6 +1611,12 @@ index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..7274dfb52ca4a08cdebcd04294cedc73 return false; } else if (!((Raider)this.mob).hasActiveRaid()) { return false; + } else { +- this.findTarget(); ++ this.findTargetAsync(); // Leaf - Async target finding + return this.target != null; + } + } diff --git a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java index abf57494950f55bbd75f335f26736cb9e703c197..efd2418f56c36e7850edde483a2a4906dd622441 100644 --- a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java From 1d067a780a36066036aaa9f3c46b8067d27dcca2 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sun, 22 Jun 2025 02:37:00 +0900 Subject: [PATCH 22/26] [ci skip] cleanup --- .../features/0238-Async-target-finding.patch | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch index ad24c441..bc727b7e 100644 --- a/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch +++ b/leaf-server/minecraft-patches/features/0238-Async-target-finding.patch @@ -1295,18 +1295,10 @@ index 16ec032d84f128fc44a836843fafef303f52b699..e3bb4c5850e25405a243aaf57e2e8b1c + // Leaf end - Async target finding } diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java -index f88f618d34fb343b31de3af1a875d6633703df71..dc90441edfa1cdd5c5e218811b0dc595e63f4e9c 100644 +index f88f618d34fb343b31de3af1a875d6633703df71..4725e5da804e6a796611c8203d08bc171ef1c344 100644 --- a/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java -@@ -7,6 +7,7 @@ import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.PathfinderMob; - import net.minecraft.world.entity.ai.attributes.Attributes; - import net.minecraft.world.entity.ai.targeting.TargetingConditions; -+import net.minecraft.world.entity.animal.horse.Llama; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - -@@ -36,14 +37,43 @@ public class TemptGoal extends Goal { +@@ -36,14 +36,43 @@ public class TemptGoal extends Goal { this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity)); } From 5bbafee8a1caa492a298bc7a74348ee0b942718d Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sun, 22 Jun 2025 03:00:38 +0800 Subject: [PATCH 23/26] Port `Avoid and discourage use of Maven Central as a CDN` from Paper & Cleanup `Configurable LibraryLoader maven repos` --- ...ourage-use-of-Maven-Central-as-a-CDN.patch | 112 ++++++++++++++++++ ...try.patch => 0004-Pufferfish-Sentry.patch} | 0 ...es.patch => 0005-Purpur-API-Changes.patch} | 0 ...imings.patch => 0006-Remove-Timings.patch} | 0 ...patch => 0007-KeYi-Player-Skull-API.patch} | 0 ...nfigurable-LibraryLoader-maven-repos.patch | 78 ------------ ...atch => 0008-Slice-Smooth-Teleports.patch} | 2 +- ...nfigurable-LibraryLoader-maven-repos.patch | 86 ++++++++++++++ ...patch => 0010-Leaves-Replay-Mod-API.patch} | 0 ... => 0011-Async-structure-locate-api.patch} | 0 ...> 0012-PlayerInventoryOverflowEvent.patch} | 0 ...3-Raytrace-AntiXray-SDK-integration.patch} | 0 12 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 leaf-api/paper-patches/features/0003-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a-CDN.patch rename leaf-api/paper-patches/features/{0003-Pufferfish-Sentry.patch => 0004-Pufferfish-Sentry.patch} (100%) rename leaf-api/paper-patches/features/{0004-Purpur-API-Changes.patch => 0005-Purpur-API-Changes.patch} (100%) rename leaf-api/paper-patches/features/{0005-Remove-Timings.patch => 0006-Remove-Timings.patch} (100%) rename leaf-api/paper-patches/features/{0006-KeYi-Player-Skull-API.patch => 0007-KeYi-Player-Skull-API.patch} (100%) delete mode 100644 leaf-api/paper-patches/features/0008-Configurable-LibraryLoader-maven-repos.patch rename leaf-api/paper-patches/features/{0007-Slice-Smooth-Teleports.patch => 0008-Slice-Smooth-Teleports.patch} (95%) create mode 100644 leaf-api/paper-patches/features/0009-Configurable-LibraryLoader-maven-repos.patch rename leaf-api/paper-patches/features/{0009-Leaves-Replay-Mod-API.patch => 0010-Leaves-Replay-Mod-API.patch} (100%) rename leaf-api/paper-patches/features/{0010-Async-structure-locate-api.patch => 0011-Async-structure-locate-api.patch} (100%) rename leaf-api/paper-patches/features/{0011-PlayerInventoryOverflowEvent.patch => 0012-PlayerInventoryOverflowEvent.patch} (100%) rename leaf-api/paper-patches/features/{0012-Raytrace-AntiXray-SDK-integration.patch => 0013-Raytrace-AntiXray-SDK-integration.patch} (100%) diff --git a/leaf-api/paper-patches/features/0003-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a-CDN.patch b/leaf-api/paper-patches/features/0003-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a-CDN.patch new file mode 100644 index 00000000..b0f3d5f7 --- /dev/null +++ b/leaf-api/paper-patches/features/0003-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a-CDN.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 18 Jun 2025 10:47:21 -0700 +Subject: [PATCH] Paper: Avoid and discourage use of Maven Central as a CDN + +Original license: GPLv3 +Original project: https://github.com/PaperMC/Paper + +https://github.com/PaperMC/Paper/commit/62b7f86dae659deb2fc450285452d7c1439f92dc + +Default LibraryLoader to Google's Maven Central mirror, add MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR, and warn on use of Maven Central with MavenLibraryResolver + +https://www.sonatype.com/blog/maven-central-and-the-tragedy-of-the-commons +https://www.sonatype.com/blog/beyond-ips-addressing-organizational-overconsumption-in-maven-central + +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +index 107705db2d82b7c191e5e625ec888e0bc3b03831..ebb52c2c8d5fe8ca25513aadae8168180a3d426e 100644 +--- a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +@@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory; + * MavenLibraryResolver resolver = new MavenLibraryResolver(); + * resolver.addDependency(new Dependency(new DefaultArtifact("org.jooq:jooq:3.17.7"), null)); + * resolver.addRepository(new RemoteRepository.Builder( +- * "central", "default", "https://repo1.maven.org/maven2/" ++ * "central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR // Paper - Avoid and discourage use of Maven Central as a CDN + * ).build()); + * } + *

+@@ -50,6 +50,24 @@ import org.slf4j.LoggerFactory; + @NullMarked + public class MavenLibraryResolver implements ClassPathLibrary { + ++ // Paper start - Avoid and discourage use of Maven Central as a CDN ++ /** ++ * The default Maven Central mirror, configurable through the {@code PAPER_DEFAULT_CENTRAL_REPOSITORY} environment ++ * variable. Use this instead of Maven Central directly when you do not have your own mirror, as using ++ * Maven Central as a CDN is against the Maven Central Terms of Service, and you will cause users to hit ++ * rate limits. ++ * ++ *

This repository is also used by the legacy {@link org.bukkit.plugin.java.LibraryLoader}.

++ */ ++ public static final String MAVEN_CENTRAL_DEFAULT_MIRROR = getDefaultMavenCentralMirror(); ++ private static final List MAVEN_CENTRAL_URLS = List.of( ++ "https://repo1.maven.org/maven2", ++ "http://repo1.maven.org/maven2", ++ "https://repo.maven.apache.org/maven2", ++ "http://repo.maven.apache.org/maven2" ++ ); ++ // Paper end - Avoid and discourage use of Maven Central as a CDN ++ + private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver"); + + private final RepositorySystem repository; +@@ -105,6 +123,14 @@ public class MavenLibraryResolver implements ClassPathLibrary { + * dependencies from + */ + public void addRepository(final RemoteRepository remoteRepository) { ++ // Paper start - Avoid and discourage use of Maven Central as a CDN ++ if (MAVEN_CENTRAL_URLS.stream().anyMatch(remoteRepository.getUrl()::startsWith)) { ++ LOGGER.warn( ++ "Use of Maven Central as a CDN is against the Maven Central Terms of Service. Use MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR instead.", ++ new RuntimeException("Plugin used Maven Central for library resolution") ++ ); ++ } ++ // Paper end - Avoid and discourage use of Maven Central as a CDN + this.repositories.add(remoteRepository); + } + +@@ -130,4 +156,17 @@ public class MavenLibraryResolver implements ClassPathLibrary { + store.addLibrary(file.toPath()); + } + } ++ ++ // Paper start - Avoid and discourage use of Maven Central as a CDN ++ private static String getDefaultMavenCentralMirror() { ++ String central = System.getenv("PAPER_DEFAULT_CENTRAL_REPOSITORY"); ++ if (central == null) { ++ central = System.getProperty("org.bukkit.plugin.java.LibraryLoader.centralURL"); ++ } ++ if (central == null) { ++ central = "https://maven-central.storage-download.googleapis.com/maven2"; ++ } ++ return central; ++ } ++ // Paper end - Avoid and discourage use of Maven Central as a CDN + } +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index 211c093ce2253e918cd40725ebf1ef172d1b9bdf..998a5278f39d13ed6b0a6d03514658f28b0d420f 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -49,6 +49,12 @@ public class LibraryLoader + public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries + public static java.util.function.Function, List> REMAPPER; // Paper - remap libraries + ++ // Paper start - Avoid and discourage use of Maven Central as a CDN ++ private static List getRepositories() { ++ return List.of(new RemoteRepository.Builder("central", "default", io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build()); ++ } ++ // Paper end - Avoid and discourage use of Maven Central as a CDN ++ + public LibraryLoader(@NotNull Logger logger) + { + this.logger = logger; +@@ -79,7 +85,7 @@ public class LibraryLoader + session.setSystemProperties( System.getProperties() ); + session.setReadOnly(); + +- this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) ); ++ this.repositories = repository.newResolutionRepositories( session, getRepositories()); // Paper - Avoid and discourage use of Maven Central as a CDN + } + + @Nullable diff --git a/leaf-api/paper-patches/features/0003-Pufferfish-Sentry.patch b/leaf-api/paper-patches/features/0004-Pufferfish-Sentry.patch similarity index 100% rename from leaf-api/paper-patches/features/0003-Pufferfish-Sentry.patch rename to leaf-api/paper-patches/features/0004-Pufferfish-Sentry.patch diff --git a/leaf-api/paper-patches/features/0004-Purpur-API-Changes.patch b/leaf-api/paper-patches/features/0005-Purpur-API-Changes.patch similarity index 100% rename from leaf-api/paper-patches/features/0004-Purpur-API-Changes.patch rename to leaf-api/paper-patches/features/0005-Purpur-API-Changes.patch diff --git a/leaf-api/paper-patches/features/0005-Remove-Timings.patch b/leaf-api/paper-patches/features/0006-Remove-Timings.patch similarity index 100% rename from leaf-api/paper-patches/features/0005-Remove-Timings.patch rename to leaf-api/paper-patches/features/0006-Remove-Timings.patch diff --git a/leaf-api/paper-patches/features/0006-KeYi-Player-Skull-API.patch b/leaf-api/paper-patches/features/0007-KeYi-Player-Skull-API.patch similarity index 100% rename from leaf-api/paper-patches/features/0006-KeYi-Player-Skull-API.patch rename to leaf-api/paper-patches/features/0007-KeYi-Player-Skull-API.patch diff --git a/leaf-api/paper-patches/features/0008-Configurable-LibraryLoader-maven-repos.patch b/leaf-api/paper-patches/features/0008-Configurable-LibraryLoader-maven-repos.patch deleted file mode 100644 index 2568be33..00000000 --- a/leaf-api/paper-patches/features/0008-Configurable-LibraryLoader-maven-repos.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> -Date: Sat, 3 Feb 2024 18:45:53 -0500 -Subject: [PATCH] Configurable LibraryLoader maven repos - -TODO - Dreeam: Support multi maven repos for lib downloading. - -Add JVM flag `-DLeaf.library-download-repo=link` to choose library download repo link. -e.g. `-DLeaf.library-download-repo=https://maven.aliyun.com/repository/public` - -diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java -index 107705db2d82b7c191e5e625ec888e0bc3b03831..77a58fc7c173b1724d44b0eeaf23b4a1b22b5fcb 100644 ---- a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java -+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java -@@ -105,7 +105,7 @@ public class MavenLibraryResolver implements ClassPathLibrary { - * dependencies from - */ - public void addRepository(final RemoteRepository remoteRepository) { -- this.repositories.add(remoteRepository); -+ this.repositories.add(org.dreeam.leaf.plugin.loader.MavenCentralMirror.getCentralRepo(remoteRepository)); // Leaf - Configurable LibraryLoader maven repos - } - - /** -diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -index 211c093ce2253e918cd40725ebf1ef172d1b9bdf..096140a91f19eb31a10631b949f4402e37e1c601 100644 ---- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -@@ -79,7 +79,19 @@ public class LibraryLoader - session.setSystemProperties( System.getProperties() ); - session.setReadOnly(); - -- this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) ); -+ // Leaf start - Configurable LibraryLoader maven repos -+ this.repositories = repository.newResolutionRepositories( -+ session, -+ List.of(org.dreeam.leaf.plugin.loader.MavenCentralMirror.getCentralRepo("https://repo.maven.apache.org/maven2")) -+ ); -+ /* // Dreeam TODO -+ this.repositories = repository.newResolutionRepositories(session, List.of( -+ new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2").build(), -+ new RemoteRepository.Builder("aliyun", "default", "https://maven.aliyun.com/repository/public").build(), -+ new RemoteRepository.Builder("tencentclound", "default", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public/").build(), -+ new RemoteRepository.Builder("huaweicloud", "default", "https://repo.huaweicloud.com/repository/maven/").build() -+ ));*/ -+ // Leaf end - Configurable LibraryLoader maven repos - } - - @Nullable -diff --git a/src/main/java/org/dreeam/leaf/plugin/loader/MavenCentralMirror.java b/src/main/java/org/dreeam/leaf/plugin/loader/MavenCentralMirror.java -new file mode 100644 -index 0000000000000000000000000000000000000000..95534cb6d771a0fe288e7c843c41b0036bdc7095 ---- /dev/null -+++ b/src/main/java/org/dreeam/leaf/plugin/loader/MavenCentralMirror.java -@@ -0,0 +1,24 @@ -+package org.dreeam.leaf.plugin.loader; -+ -+import org.eclipse.aether.repository.RemoteRepository; -+ -+public class MavenCentralMirror { -+ -+ public static final String MAVEN_CENTRAL_MIRROR_REPO = System.getProperty("Leaf.library-download-repo"); -+ -+ public static RemoteRepository getCentralRepo(RemoteRepository repo) { -+ if (MAVEN_CENTRAL_MIRROR_REPO != null && repo.getUrl().contains("repo.maven.apache.org/maven2")) { -+ repo = new RemoteRepository.Builder("central", "default", MAVEN_CENTRAL_MIRROR_REPO).build(); -+ } -+ -+ return repo; -+ } -+ -+ public static RemoteRepository getCentralRepo(String repo) { -+ if (MAVEN_CENTRAL_MIRROR_REPO != null) { -+ repo = MAVEN_CENTRAL_MIRROR_REPO; -+ } -+ -+ return new RemoteRepository.Builder("central", "default", repo).build(); -+ } -+} diff --git a/leaf-api/paper-patches/features/0007-Slice-Smooth-Teleports.patch b/leaf-api/paper-patches/features/0008-Slice-Smooth-Teleports.patch similarity index 95% rename from leaf-api/paper-patches/features/0007-Slice-Smooth-Teleports.patch rename to leaf-api/paper-patches/features/0008-Slice-Smooth-Teleports.patch index 651e7397..c75b4a33 100644 --- a/leaf-api/paper-patches/features/0007-Slice-Smooth-Teleports.patch +++ b/leaf-api/paper-patches/features/0008-Slice-Smooth-Teleports.patch @@ -9,7 +9,7 @@ Original project: https://github.com/Cryptite/Slice Co-authored-by: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 2a8abee51e8fad62b0aa58a47eadfbac2bf51fdf..716f99b4d09ffd415f8a53a90031c92d8931f125 100644 +index 69f7a2fa54b667f2bb97454d6be9f6322a9aa43d..c92e0bb60504900fa1d1e7c86534a46578c91799 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -3709,6 +3709,33 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/leaf-api/paper-patches/features/0009-Configurable-LibraryLoader-maven-repos.patch b/leaf-api/paper-patches/features/0009-Configurable-LibraryLoader-maven-repos.patch new file mode 100644 index 00000000..151b87cc --- /dev/null +++ b/leaf-api/paper-patches/features/0009-Configurable-LibraryLoader-maven-repos.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> +Date: Sat, 3 Feb 2024 18:45:53 -0500 +Subject: [PATCH] Configurable LibraryLoader maven repos + +Add JVM flag `-DLeaf.library-download-repo=link` to choose library download repo link. +e.g. `-DLeaf.library-download-repo=https://maven.aliyun.com/repository/public` + +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +index ebb52c2c8d5fe8ca25513aadae8168180a3d426e..006a86da6afa1b7b80df5df073ebd236e27cd2b5 100644 +--- a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +@@ -60,12 +60,16 @@ public class MavenLibraryResolver implements ClassPathLibrary { + *

This repository is also used by the legacy {@link org.bukkit.plugin.java.LibraryLoader}.

+ */ + public static final String MAVEN_CENTRAL_DEFAULT_MIRROR = getDefaultMavenCentralMirror(); +- private static final List MAVEN_CENTRAL_URLS = List.of( ++ // Leaf start - Configurable LibraryLoader maven repos ++ @org.jspecify.annotations.Nullable ++ public static final RemoteRepository MAVEN_CENTRAL_MIRROR_REPO = getCentralMirrorRepo(); ++ private static final String[] MAVEN_CENTRAL_URLS = new String[]{ + "https://repo1.maven.org/maven2", + "http://repo1.maven.org/maven2", + "https://repo.maven.apache.org/maven2", + "http://repo.maven.apache.org/maven2" +- ); ++ }; ++ // Leaf end - Configurable LibraryLoader maven repos + // Paper end - Avoid and discourage use of Maven Central as a CDN + + private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver"); +@@ -124,12 +128,21 @@ public class MavenLibraryResolver implements ClassPathLibrary { + */ + public void addRepository(final RemoteRepository remoteRepository) { + // Paper start - Avoid and discourage use of Maven Central as a CDN +- if (MAVEN_CENTRAL_URLS.stream().anyMatch(remoteRepository.getUrl()::startsWith)) { +- LOGGER.warn( +- "Use of Maven Central as a CDN is against the Maven Central Terms of Service. Use MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR instead.", +- new RuntimeException("Plugin used Maven Central for library resolution") +- ); ++ // Leaf start - Configurable LibraryLoader maven repos ++ for (String url : MAVEN_CENTRAL_URLS) { ++ if (remoteRepository.getUrl().startsWith(url)) { ++ RemoteRepository mirrorRepo = MAVEN_CENTRAL_MIRROR_REPO; ++ if (mirrorRepo != null) { ++ this.repositories.add(mirrorRepo); ++ return; ++ } ++ LOGGER.warn( ++ "Use of Maven Central as a CDN is against the Maven Central Terms of Service. Use MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR instead.", ++ new RuntimeException("Plugin used Maven Central for library resolution") ++ ); ++ } + } ++ // Leaf end - Configurable LibraryLoader maven repos + // Paper end - Avoid and discourage use of Maven Central as a CDN + this.repositories.add(remoteRepository); + } +@@ -169,4 +182,15 @@ public class MavenLibraryResolver implements ClassPathLibrary { + return central; + } + // Paper end - Avoid and discourage use of Maven Central as a CDN ++ ++ // Leaf start - Configurable LibraryLoader maven repos ++ @org.jspecify.annotations.Nullable ++ private static RemoteRepository getCentralMirrorRepo() { ++ String mirrorAddr = System.getProperty("Leaf.library-download-repo"); ++ if (mirrorAddr != null) { ++ new RemoteRepository.Builder("central", "default", mirrorAddr).build(); ++ } ++ return null; ++ } ++ // Leaf end - Configurable LibraryLoader maven repos + } +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index 998a5278f39d13ed6b0a6d03514658f28b0d420f..2b4f6f305d3e4418b912e36a6b603c412111947f 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -51,6 +51,7 @@ public class LibraryLoader + + // Paper start - Avoid and discourage use of Maven Central as a CDN + private static List getRepositories() { ++ if (io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver.MAVEN_CENTRAL_MIRROR_REPO != null) return List.of(io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver.MAVEN_CENTRAL_MIRROR_REPO); // Leaf - Configurable LibraryLoader maven repos + return List.of(new RemoteRepository.Builder("central", "default", io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build()); + } + // Paper end - Avoid and discourage use of Maven Central as a CDN diff --git a/leaf-api/paper-patches/features/0009-Leaves-Replay-Mod-API.patch b/leaf-api/paper-patches/features/0010-Leaves-Replay-Mod-API.patch similarity index 100% rename from leaf-api/paper-patches/features/0009-Leaves-Replay-Mod-API.patch rename to leaf-api/paper-patches/features/0010-Leaves-Replay-Mod-API.patch diff --git a/leaf-api/paper-patches/features/0010-Async-structure-locate-api.patch b/leaf-api/paper-patches/features/0011-Async-structure-locate-api.patch similarity index 100% rename from leaf-api/paper-patches/features/0010-Async-structure-locate-api.patch rename to leaf-api/paper-patches/features/0011-Async-structure-locate-api.patch diff --git a/leaf-api/paper-patches/features/0011-PlayerInventoryOverflowEvent.patch b/leaf-api/paper-patches/features/0012-PlayerInventoryOverflowEvent.patch similarity index 100% rename from leaf-api/paper-patches/features/0011-PlayerInventoryOverflowEvent.patch rename to leaf-api/paper-patches/features/0012-PlayerInventoryOverflowEvent.patch diff --git a/leaf-api/paper-patches/features/0012-Raytrace-AntiXray-SDK-integration.patch b/leaf-api/paper-patches/features/0013-Raytrace-AntiXray-SDK-integration.patch similarity index 100% rename from leaf-api/paper-patches/features/0012-Raytrace-AntiXray-SDK-integration.patch rename to leaf-api/paper-patches/features/0013-Raytrace-AntiXray-SDK-integration.patch From 60539427ff72517363c6df3e9640d44a9ecc5ea2 Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sun, 22 Jun 2025 03:15:03 +0800 Subject: [PATCH 24/26] Cleanup patch --- ... => 0189-Paper-Fix-excess-slot-updates.patch} | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) rename leaf-server/minecraft-patches/features/{0189-Paper-Fix-excess-slot-updates-inventory-state-id-des.patch => 0189-Paper-Fix-excess-slot-updates.patch} (67%) diff --git a/leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates-inventory-state-id-des.patch b/leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates.patch similarity index 67% rename from leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates-inventory-state-id-des.patch rename to leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates.patch index d921c5df..cce1462f 100644 --- a/leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates-inventory-state-id-des.patch +++ b/leaf-server/minecraft-patches/features/0189-Paper-Fix-excess-slot-updates.patch @@ -1,12 +1,16 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Taiyou06 -Date: Wed, 11 Jun 2025 20:51:36 +0200 -Subject: [PATCH] Paper: Fix excess slot updates / inventory state id desync +From: AJ Ferguson +Date: Mon, 6 Jan 2025 20:31:00 +1100 +Subject: [PATCH] Paper: Fix excess slot updates -Original Patch: https://github.com/PaperMC/Paper/pull/12654 +Original license: GPLv3 +Original project: https://github.com/PaperMC/Paper +Paper pull request: https://github.com/PaperMC/Paper/pull/12654 + +https://github.com/PaperMC/Paper/commit/e714de636543d61fcd3682705484c8a15f4f3ca6 diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java -index ff2ff95ec9d94e2e31e8174196b384c37d56f38a..2a49a0bdeb61c4fadddc241c8ebca908959d7e9c 100644 +index ff2ff95ec9d94e2e31e8174196b384c37d56f38a..3ffc454609adc82c6a4daba68efac129bee38eb5 100644 --- a/net/minecraft/world/inventory/AbstractContainerMenu.java +++ b/net/minecraft/world/inventory/AbstractContainerMenu.java @@ -553,7 +553,7 @@ public abstract class AbstractContainerMenu { @@ -14,7 +18,7 @@ index ff2ff95ec9d94e2e31e8174196b384c37d56f38a..2a49a0bdeb61c4fadddc241c8ebca908 slot.setChanged(); // CraftBukkit start - Make sure the client has the right slot contents - if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != 64) { -+ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != net.minecraft.world.Container.MAX_STACK) { ++ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != Container.MAX_STACK) { // Paper - craftbukkkit - Fix excess slot updates serverPlayer.connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem())); // Updating a crafting inventory makes the client reset the result slot, have to send it again if (this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.WORKBENCH || this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.CRAFTING) { From 3ab4a104c3dd4b521d2b002afbb64dfb89c92b82 Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sun, 22 Jun 2025 09:00:32 +0800 Subject: [PATCH 25/26] Revert rewriting rules to fix compatibility with Nova --- .../work/server}/0062-Add-missing-rewrite-rules.patch | 9 +++++++++ 1 file changed, 9 insertions(+) rename {leaf-server/paper-patches/features => leaf-archived-patches/work/server}/0062-Add-missing-rewrite-rules.patch (79%) diff --git a/leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch b/leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch similarity index 79% rename from leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch rename to leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch index 43921cad..fe3c123f 100644 --- a/leaf-server/paper-patches/features/0062-Add-missing-rewrite-rules.patch +++ b/leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch @@ -3,6 +3,15 @@ From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> Date: Tue, 9 Nov 2077 00:00:00 +0800 Subject: [PATCH] Add missing rewrite rules +TODO: needs to check and fix it. +The new added rewriting rules cause incompatible with Nova plugin (The call Registry<*>::freeze in RegistryEventsPatch#transform) +It breaks kotlin reflection, makes it can't get all members of Registry class and its parent interfaces. +to validate using Nova plugin: +``` +println(net.minecraft.core.Registry::class.members.size) +println(net.minecraft.core.Registry::class.java.methods.size) +``` + Tracking PR: https://github.com/PaperMC/asm-utils/pull/48 diff --git a/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java b/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java From 42a68c9fc4376417fa41948e3458acda8513276a Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:52:42 +0800 Subject: [PATCH 26/26] [ci skip] Revert "Fetch all commits to fix download api" This reverts commit d46c4bca937b2aa761a2573133c9f286d4a9349d. --- .github/workflows/build-1215.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-1215.yml b/.github/workflows/build-1215.yml index 81f92a08..1a21f932 100644 --- a/.github/workflows/build-1215.yml +++ b/.github/workflows/build-1215.yml @@ -134,7 +134,7 @@ jobs: BRANCH="${{ github.ref_name }}" REPO_DIR="/root/Leaf-${BRANCH//\//-}" # Replace slashes with dashes to avoid directory issues - [ -d "$REPO_DIR/.git" ] && cd "$REPO_DIR" && git fetch origin && git checkout "$BRANCH" && git reset --hard "origin/$BRANCH" || git clone --branch "$BRANCH" https://github.com/Winds-Studio/Leaf "$REPO_DIR" + [ -d "$REPO_DIR/.git" ] && cd "$REPO_DIR" && git fetch origin && git checkout "$BRANCH" && git reset --hard "origin/$BRANCH" || git clone --branch "$BRANCH" --depth 1 https://github.com/Winds-Studio/Leaf "$REPO_DIR" # Proceed to insert the build into the API cd ~/api/cli