dependencies = new ArrayList<>();
+
++ // 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[]{
++ };
++ // Leaf end - Configurable LibraryLoader maven repos
++
+ /**
+ * Creates a new maven library resolver instance.
+ *
+@@ -102,9 +111,24 @@ public class MavenLibraryResolver implements ClassPathLibrary {
+ * repository.
+ *
+ * @param remoteRepository the configuration that defines the maven repository this library resolver should fetch
+- * dependencies from
++ * 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
++ // 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
+ this.repositories.add(remoteRepository);
}
- /**
+@@ -130,4 +154,15 @@ public class MavenLibraryResolver implements ClassPathLibrary {
+ store.addLibrary(file.toPath());
+ }
+ }
++
++ // 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 cfe41c0a67c8d729b6bd23b0cfa32db3c9db9f74..9f167a9cb4a93a79b8ed709b61214ce0138a875d 100644
+index cfe41c0a67c8d729b6bd23b0cfa32db3c9db9f74..05d3b793bf9cb320774f9f488a3b78bedab6a9d4 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 {
- session.setSystemProperties(System.getProperties());
- session.setReadOnly();
+@@ -47,6 +47,8 @@ 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
-- 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
- }
++ 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
++
+ public LibraryLoader(@NotNull Logger logger) {
+ this.logger = logger;
- @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-archived-patches/removed/hardfork/api/0004-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a.patch b/leaf-archived-patches/removed/hardfork/api/0004-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a.patch
new file mode 100644
index 00000000..6c8f08ba
--- /dev/null
+++ b/leaf-archived-patches/removed/hardfork/api/0004-Paper-Avoid-and-discourage-use-of-Maven-Central-as-a.patch
@@ -0,0 +1,124 @@
+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
+
+Removed since Leaf 1.21.6, added in Paper
+
+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 7e4e702845f61703f0741add59f7cfc0afea1543..012ba8ee3d84a7bb09068e42fd1bae8ad221622e 100644
+--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
+@@ -47,19 +47,11 @@ 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
+
+- // TODO: Consider moving this and adding per plugin support for defining repositories
++ // Paper start - Avoid and discourage use of Maven Central as a CDN
+ private static List getRepositories() {
+- 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://repo.maven.apache.org/maven2";
+- }
+-
+- return Arrays.asList(new RemoteRepository.Builder("central", "default", central).build());
+-
++ 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;
+@@ -87,7 +79,7 @@ public class LibraryLoader {
+ session.setSystemProperties(System.getProperties());
+ session.setReadOnly();
+
+- this.repositories = repository.newResolutionRepositories(session, getRepositories());
++ this.repositories = repository.newResolutionRepositories(session, getRepositories()); // Paper - Avoid and discourage use of Maven Central as a CDN
+ }
+
+ @Nullable
diff --git a/leaf-server/minecraft-patches/features/0274-PaperPR-Fix-excess-slot-updates-inventory-state-id-d.patch b/leaf-archived-patches/removed/hardfork/server/0275-Paper-Fix-excess-slot-updates.patch
similarity index 58%
rename from leaf-server/minecraft-patches/features/0274-PaperPR-Fix-excess-slot-updates-inventory-state-id-d.patch
rename to leaf-archived-patches/removed/hardfork/server/0275-Paper-Fix-excess-slot-updates.patch
index 24f71905..41e1a530 100644
--- a/leaf-server/minecraft-patches/features/0274-PaperPR-Fix-excess-slot-updates-inventory-state-id-d.patch
+++ b/leaf-archived-patches/removed/hardfork/server/0275-Paper-Fix-excess-slot-updates.patch
@@ -1,23 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Leymooo
-Date: Wed, 11 Jun 2025 05:30:39 +0300
-Subject: [PATCH] PaperPR: 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
+
+Removed since Leaf 1.21.6, added in Paper
Original license: GPLv3
-Original project: https://github.com/SparklyPower/SparklyPaper
+Original project: https://github.com/PaperMC/Paper
Paper pull request: https://github.com/PaperMC/Paper/pull/12654
-Fixes inventory state id desync with high ping causing inventory to be "buggy" (ghost items, items jumping to/from cursor, etc)
-
-Without patch: https://youtu.be/hOXt3Rpkgtg
-With patch: https://youtu.be/MtOYD7uieS4
-
-https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/df01cf867a2255024aacf9ac2ff6a56b2ffb7ce5#nms-patches/net/minecraft/world/inventory/Container.patch
-
-https://discord.com/channels/289587909051416579/555462289851940864/1382165293308182699
+https://github.com/PaperMC/Paper/commit/e714de636543d61fcd3682705484c8a15f4f3ca6
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
-index 9dd3187fd968ab95e9d55b4c8cc74e782cc0f241..c5ede24d00f444d04c835af3a7f0154227492be4 100644
+index 9dd3187fd968ab95e9d55b4c8cc74e782cc0f241..46c3353a9722cb9c8073cadbad0ced57bab0c390 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -559,7 +559,7 @@ public abstract class AbstractContainerMenu {
@@ -25,7 +20,7 @@ index 9dd3187fd968ab95e9d55b4c8cc74e782cc0f241..c5ede24d00f444d04c835af3a7f01542
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) { // Paper - Fix excess slot updates / inventory state id desync
++ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != Container.MAX_STACK) { // Paper - craftbukkkit - Fix excess slot updates
serverPlayer.connection.send(new net.minecraft.network.protocol.game.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) {
diff --git a/leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch b/leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch
new file mode 100644
index 00000000..fe3c123f
--- /dev/null
+++ b/leaf-archived-patches/work/server/0062-Add-missing-rewrite-rules.patch
@@ -0,0 +1,36 @@
+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
+
+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
+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()
+ );
+
diff --git a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch b/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch
index 828d7b47..9daee4e7 100644
--- a/leaf-server/minecraft-patches/features/0178-Asynchronous-locator.patch
+++ b/leaf-server/minecraft-patches/features/0178-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 a734b2597c3491db35d9660e169f8e8b6320900b..8a79a339757d6ac49713bf6db0fb675d9893fd1b 100644
+index a734b2597c3491db35d9660e169f8e8b6320900b..5274f09b0abf148aea1c0baa39edbfdac1acc4f5 100644
--- a/net/minecraft/server/commands/LocateCommand.java
+++ b/net/minecraft/server/commands/LocateCommand.java
-@@ -106,6 +106,38 @@ public class LocateCommand {
+@@ -106,6 +106,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 eaaa66c4d86d4ebda0acf8f1dbe8ecb55aa28285..8f41326fda8c5f9f6926038508be6c6529b051bc 100644
+--- a/net/minecraft/server/level/ServerChunkCache.java
++++ b/net/minecraft/server/level/ServerChunkCache.java
+@@ -852,14 +852,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 23696a5e2871ea07f34d4b4f6a20e2896ac3f5bd..c4fda92e078c9ba745b2548ecaaffffff97fb0fd 100644
--- a/net/minecraft/world/entity/animal/Dolphin.java
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 1f922183..41ad8fa9 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 50630dabe4220b8ac810a0395d70360879fdeabc..2e03020a67c7f59a3c554ab720fba831
// Gale start - Pufferfish - SIMD support
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index ce39571c292c0dd58075e159c343898a374f008a..117a8ef98c369bf0919e44fe823d6af0758816b5 100644
+index ce39571c292c0dd58075e159c343898a374f008a..27da552e2542153a58d6177f592cf30d858c41a9 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -175,7 +175,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -163,26 +163,13 @@ index ce39571c292c0dd58075e159c343898a374f008a..117a8ef98c369bf0919e44fe823d6af0
@Override
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
-@@ -337,6 +347,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);
-@@ -707,6 +723,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
+@@ -707,6 +717,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 ce39571c292c0dd58075e159c343898a374f008a..117a8ef98c369bf0919e44fe823d6af0
}
// Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
-@@ -980,12 +1003,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
- }
-@@ -1468,6 +1493,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) {
-@@ -1484,6 +1510,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 4a1a336914eff8a178dcd992bd1bfea25a8be76b..dbfd7301c7b2644ac26a5ee3f804236ee48f5aed 100644
+index 4a1a336914eff8a178dcd992bd1bfea25a8be76b..7e3b35df01b63735fd4d5202788477a1342708a5 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -138,6 +138,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
@@ -238,68 +194,39 @@ index 4a1a336914eff8a178dcd992bd1bfea25a8be76b..dbfd7301c7b2644ac26a5ee3f804236e
protected Mob(EntityType extends Mob> entityType, Level level) {
super(entityType, level);
-@@ -216,12 +222,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;
+@@ -222,6 +228,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
-@@ -782,17 +798,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;
+@@ -793,6 +804,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 extends Animal> entitiesOfClass = this.animal
.level()
.getEntitiesOfClass((Class extends Animal>)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 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b9f8b0cc0 100644
+index 55f1c138039b80894f655d180192f5cb95e32778..1afc0a13ff7f64e453b272c1d94b7e4c80cc22dd 100644
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -25,12 +25,22 @@ public class GoalSelector {
@@ -702,13 +629,13 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
// Paper end - Perf: optimize goal types
if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) {
-@@ -83,7 +94,131 @@ public class GoalSelector {
+@@ -83,7 +94,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) {
@@ -727,7 +654,12 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
+ 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;
@@ -775,7 +707,7 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
+ 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 -> {}
+ }
+ }
@@ -820,12 +752,12 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
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;
+ }
@@ -834,7 +766,7 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
for (WrappedGoal wrappedGoal : this.availableGoals) {
if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
wrappedGoal.stop();
-@@ -114,6 +249,18 @@ public class GoalSelector {
+@@ -114,6 +254,24 @@ public class GoalSelector {
}
public void tickRunningGoals(boolean tickAllRunning) {
@@ -846,6 +778,12 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
+ 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;
+ }
@@ -854,14 +792,14 @@ index 55f1c138039b80894f655d180192f5cb95e32778..2046bc2b69e0e41f31b794d0bda7df4b
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..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 {
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);
@@ -910,16 +848,16 @@ 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) {
++ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (llama == null) {
+ findTargetAsync();
+ return false;
@@ -927,20 +865,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;
@@ -949,7 +887,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;
@@ -957,19 +895,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;
+ }
@@ -1059,23 +997,23 @@ 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 f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0b3c29eb3 100644
+index f15da598cb1d7872fafb8b173e5134b9667c9a9f..13b7129774a098c66990266e03877302f5cea0fe 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));
}
-+ // 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)
-+ || !this.mob.isWithinHome(blockPos1)
++ || !this.mob.isWithinRestriction(blockPos1)
+ || !this.isValidTarget(this.mob.level(), blockPos1)) {
+ return false;
+ }
@@ -1084,10 +1022,15 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ 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;
@@ -1100,9 +1043,10 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ final int searchRange = this.searchRange;
+ final int verticalSearchRange = this.verticalSearchRange;
+ final BlockPos blockPos = mob.blockPosition();
-+ final float homeRadius = mob.getHomeRadius();
-+ final BlockPos homePosition = mob.getHomePosition();
-+ ctx.wake = () -> findNearestBlockAsync(ty, toRemove, mob, serverLevel, verticalSearchStart, searchRange, verticalSearchRange, blockPos, homeRadius, homePosition);
++ 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 {
@@ -1115,37 +1059,32 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ Strider,
+ TurtleToWater,
+ TurtleLay,
++ Unknown,
+ }
-+ // 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;
-@@ -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 search block
-+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) {
-+ getBlockAsync();
-+ return false;
-+ }
-+ // Leaf end - Async search block
- 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;
}
-+ // 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,
@@ -1155,8 +1094,8 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ final int searchRange,
+ final int verticalSearchRange,
+ final BlockPos blockPos,
-+ final float homeRadius,
-+ final BlockPos homePosition
++ final float restrictRadius,
++ final BlockPos restrictCenter
+ ) {
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+ for (int i2 = verticalSearchStart; i2 <= verticalSearchRange; i2 = i2 > 0 ? -i2 : 1 - i2) {
@@ -1165,7 +1104,7 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ for (int i5 = i4 < i3 && i4 > -i3 ? i3 : 0; i5 <= i3; i5 = i5 > 0 ? -i5 : 1 - i5) {
+ mutableBlockPos.setWithOffset(blockPos, i4, i2 - 1, i5);
+ if (!serverLevel.hasChunkAt(mutableBlockPos)) continue;
-+ if (isWithinHome(homeRadius, homePosition, mutableBlockPos)
++ if (isWithinRestriction(restrictRadius, restrictCenter, mutableBlockPos)
+ && isValidTargetAsync(ty, toRemove, mob, serverLevel, mutableBlockPos)) {
+ return mutableBlockPos.immutable();
+ }
@@ -1176,15 +1115,17 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ return null;
+ }
+
-+ private static boolean isWithinHome(float homeRadius, BlockPos homePosition, BlockPos pos) {
-+ return homeRadius == -1.0F || homePosition.distSqr(pos) < homeRadius * homeRadius;
++ 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
-+ protected abstract TypeToCheck typeToCheck();
++ // Leaf start - Async target finding
++ protected TypeToCheck typeToCheck() {
++ return TypeToCheck.Unknown;
++ }
+
+ private static boolean isValidTargetAsync(
+ TypeToCheck type,
@@ -1242,20 +1183,21 @@ index f15da598cb1d7872fafb8b173e5134b9667c9a9f..7a870c4efcb1022790f9baf1bac0f3c0
+ 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 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) {
@@ -1269,7 +1211,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(
@@ -1278,7 +1220,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);
@@ -1305,57 +1247,61 @@ 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..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;
- } 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;
- } 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
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 a805c9426630c2c46db9d0dd536f1d16769395d3..8842e87b652635db72bac07a9c4883f79c48e700 100644
+index a805c9426630c2c46db9d0dd536f1d16769395d3..66445cf3aa824a1294959eb3ae41a1807bb18f42 100644
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
-@@ -49,12 +49,51 @@ public class TemptGoal extends Goal {
+@@ -49,14 +49,43 @@ 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);
@@ -1374,58 +1320,42 @@ index a805c9426630c2c46db9d0dd536f1d16769395d3..8842e87b652635db72bac07a9c4883f7
+ .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
+- 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 Tempt Finding
- this.player = getServerLevel(this.mob)
- .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
++ // Leaf end - Async target finding
// 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..6e752caa969891fa7f44b69ab58fca5434bb1aa9 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
-@@ -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 {
+@@ -24,13 +24,52 @@ 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);
+ 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;
+ }
@@ -1450,33 +1380,37 @@ index fb160a59c873d5c3f2c3d31966ca1a653f1b384d..6e752caa969891fa7f44b69ab58fca54
+ return null;
+ };
+ }
-+ // Leaf end - Async Target Finding
++ // Leaf end - Async target finding
+
@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 extends LivingEntity> 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..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 {
@@ -1484,7 +1418,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();
@@ -1521,7 +1455,7 @@ index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..212934d7a2adc20c808ab204232dfa1e
+ };
+ return;
+ }
-+ // Leaf end - Async alert other
++ // Leaf end - Async target finding
+
List extends Mob> entitiesOfClass = this.mob
.level()
@@ -1531,7 +1465,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) {
@@ -1540,7 +1474,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;
@@ -1548,7 +1482,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();
@@ -1576,20 +1510,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..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);
}
-+ // 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);
@@ -1598,7 +1532,12 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e113
+ 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;
@@ -1617,7 +1556,7 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e113
+ }
+ };
+ }
-+ // Leaf end - Async Target Finding
++ // Leaf end - Async target finding
+
@Override
public boolean canUse() {
@@ -1629,27 +1568,24 @@ index 1cd8143c938237ce035fa866d4f2ed1e2cd1ebca..211178240d9f58504ff822e459f3e113
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() {
@@ -1666,6 +1602,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
@@ -1688,14 +1630,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();
@@ -1715,7 +1657,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc
+ };
+ return;
+ }
-+ // Leaf end - Async alert other
++ // Leaf end - Async target finding
this.getNearbyMobsOfSameType()
.stream()
.filter(mob -> mob != this.mob)
@@ -1723,7 +1665,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) {
@@ -1732,10 +1674,10 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..270f0b8b33aed1c54edbdb8595ce7fcc
+ }
+ }
+ }
-+ // Leaf end - Async alert other
++ // Leaf end - Async target finding
+
private List extends Mob> 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 extends Mob>)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS);
@@ -1780,7 +1722,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 8964bb5098c0dc36741af3656af6bc0b5b463abe..ac35459445061f50302f70044e81a5967e03df5f 100644
+index 8964bb5098c0dc36741af3656af6bc0b5b463abe..a22ccaab0f4d6e3a69080b56f8042010403378cf 100644
--- a/net/minecraft/world/entity/animal/Fox.java
+++ b/net/minecraft/world/entity/animal/Fox.java
@@ -867,6 +867,11 @@ public class Fox extends Animal {
@@ -1809,7 +1751,7 @@ index 8964bb5098c0dc36741af3656af6bc0b5b463abe..ac35459445061f50302f70044e81a596
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 +1760,24 @@ index 8964bb5098c0dc36741af3656af6bc0b5b463abe..ac35459445061f50302f70044e81a596
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 02bfa88568e635770675ea9173f2cf3ca21457fa..c7dc46c1584345463100264dc88bddb7d883575e 100644
+index 02bfa88568e635770675ea9173f2cf3ca21457fa..8b37cbae45916227b99c7dae4da5f0c0e3144619 100644
--- a/net/minecraft/world/entity/animal/Panda.java
+++ b/net/minecraft/world/entity/animal/Panda.java
@@ -989,9 +989,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 +1788,12 @@ index 02bfa88568e635770675ea9173f2cf3ca21457fa..c7dc46c1584345463100264dc88bddb7
+ 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 1af1b33702296f9aa74c33436ea2904c5e5ae43d..ad9a1baa24a7a4ac22bb741f743e5b32514e318a 100644
+index 1af1b33702296f9aa74c33436ea2904c5e5ae43d..da19a60713ef159b86f98e1e718a1776493cdec6 100644
--- a/net/minecraft/world/entity/animal/Rabbit.java
+++ b/net/minecraft/world/entity/animal/Rabbit.java
@@ -670,7 +670,13 @@ public class Rabbit extends Animal {
@@ -1859,13 +1801,13 @@ index 1af1b33702296f9aa74c33436ea2904c5e5ae43d..ad9a1baa24a7a4ac22bb741f743e5b32
}
- 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 +1816,7 @@ index 1af1b33702296f9aa74c33436ea2904c5e5ae43d..ad9a1baa24a7a4ac22bb741f743e5b32
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 +1825,17 @@ index 1af1b33702296f9aa74c33436ea2904c5e5ae43d..ad9a1baa24a7a4ac22bb741f743e5b32
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 9bdc1f10e3b40672449ad166f130ecabdacc75d3..49e54711a5a57541cb603fa0bf9f5acd739453a6 100644
+index 9bdc1f10e3b40672449ad166f130ecabdacc75d3..98131b65eaaa5e20b8f4e8d022141140b70521ca 100644
--- a/net/minecraft/world/entity/animal/Turtle.java
+++ b/net/minecraft/world/entity/animal/Turtle.java
@@ -483,8 +483,15 @@ public class Turtle extends Animal {
@@ -1901,15 +1843,15 @@ index 9bdc1f10e3b40672449ad166f130ecabdacc75d3..49e54711a5a57541cb603fa0bf9f5acd
@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 +1860,20 @@ index 9bdc1f10e3b40672449ad166f130ecabdacc75d3..49e54711a5a57541cb603fa0bf9f5acd
@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 7e7cb9db1c84bdb173b444bec90663a93fb3b549..e64713d454b6b00827c609b36371d841adc30df0 100644
+index 7e7cb9db1c84bdb173b444bec90663a93fb3b549..96016902084a94a98c850579ec7714264a23b781 100644
--- a/net/minecraft/world/entity/animal/wolf/Wolf.java
+++ b/net/minecraft/world/entity/animal/wolf/Wolf.java
@@ -710,7 +710,7 @@ public class Wolf extends TamableAnimal implements NeutralMob {
@@ -1939,12 +1881,12 @@ index 7e7cb9db1c84bdb173b444bec90663a93fb3b549..e64713d454b6b00827c609b36371d841
@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 7ff380212ce5e56e0e58e5f52f8c75bda5061ef0..11b10d802b7a63cc294c66c70c9a99b48b601632 100644
+index 7ff380212ce5e56e0e58e5f52f8c75bda5061ef0..c21519490433dfb2da3435afe757df01747c98e5 100644
--- a/net/minecraft/world/entity/monster/Drowned.java
+++ b/net/minecraft/world/entity/monster/Drowned.java
@@ -392,7 +392,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
@@ -1952,7 +1894,7 @@ index 7ff380212ce5e56e0e58e5f52f8c75bda5061ef0..11b10d802b7a63cc294c66c70c9a99b4
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
@@ -1961,24 +1903,24 @@ index 7ff380212ce5e56e0e58e5f52f8c75bda5061ef0..11b10d802b7a63cc294c66c70c9a99b4
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 58887b2cc931892f96793edd7a7d1db22cb8686c..769f3a350ebe0133a2b45e13fe9cf9456d5d9748 100644
+index 58887b2cc931892f96793edd7a7d1db22cb8686c..573986e139321cd8389440ac2a9a50f806b4ed8c 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
@@ -588,10 +588,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;
@@ -1991,12 +1933,12 @@ index 58887b2cc931892f96793edd7a7d1db22cb8686c..769f3a350ebe0133a2b45e13fe9cf945
+ 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);
@@ -2004,13 +1946,13 @@ index 58887b2cc931892f96793edd7a7d1db22cb8686c..769f3a350ebe0133a2b45e13fe9cf945
+ 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 {
@@ -2018,31 +1960,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 22afb73cd31c15ed7c68c403f044910d93889d99..f407daf04f2e498dfc058a7bc8b062f80cdccdc7 100644
+index 22afb73cd31c15ed7c68c403f044910d93889d99..44b9fb5fbbce0fab5b09425078c31058b8576579 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
-@@ -1532,6 +1532,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
-@@ -1793,9 +1794,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl
+@@ -1793,9 +1793,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl
@Override
public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate super Entity> predicate) {
@@ -2050,9 +1984,9 @@ index 22afb73cd31c15ed7c68c403f044910d93889d99..f407daf04f2e498dfc058a7bc8b062f8
- 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/0275-Fix-crash-during-parsing-unknown-command-message.patch b/leaf-server/minecraft-patches/features/0274-Fix-crash-during-parsing-unknown-command-message.patch
similarity index 100%
rename from leaf-server/minecraft-patches/features/0275-Fix-crash-during-parsing-unknown-command-message.patch
rename to leaf-server/minecraft-patches/features/0274-Fix-crash-during-parsing-unknown-command-message.patch
diff --git a/leaf-server/minecraft-patches/features/0275-optimize-random-tick.patch b/leaf-server/minecraft-patches/features/0275-optimize-random-tick.patch
new file mode 100644
index 00000000..1b14456a
--- /dev/null
+++ b/leaf-server/minecraft-patches/features/0275-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 46e171ca454253c32e22c0c18587e9a7ba19f331..36e592ff42eba050829f9c4d055c3d49a78ba813 100644
+--- a/net/minecraft/server/level/ServerChunkCache.java
++++ b/net/minecraft/server/level/ServerChunkCache.java
+@@ -633,6 +633,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 27da552e2542153a58d6177f592cf30d858c41a9..a180612fea46ec9f7dcfe1781e985dd2e98ed513 100644
+--- a/net/minecraft/server/level/ServerLevel.java
++++ b/net/minecraft/server/level/ServerLevel.java
+@@ -1114,6 +1114,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();
+@@ -1129,7 +1130,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 a3674ddb883eecb255279375a5e2eece7e016c0f..634bf0c15eb63aeb5ff06dd9b43ecbab627b0128 100644
+--- a/net/minecraft/world/level/chunk/LevelChunk.java
++++ b/net/minecraft/world/level/chunk/LevelChunk.java
+@@ -152,6 +152,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);
+ }
+@@ -416,6 +458,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/0278-Paw-optimization.patch b/leaf-server/minecraft-patches/features/0278-Paw-optimization.patch
index d7fb58da..2aa176bc 100644
--- a/leaf-server/minecraft-patches/features/0278-Paw-optimization.patch
+++ b/leaf-server/minecraft-patches/features/0278-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 12cf6dc9bac109a4feeeeede5f3762b20ea582bb..b450ac5e19d42765c739311de1566b7b0c11c88b 100644
+index 36e592ff42eba050829f9c4d055c3d49a78ba813..b32cb1c85a9f7a7a96a257c4546ee7e21cd91a6d 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -623,8 +623,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -117,10 +117,10 @@ index 12cf6dc9bac109a4feeeeede5f3762b20ea582bb..b450ac5e19d42765c739311de1566b7b
for (LevelChunk levelChunk : list) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70ccd672ad0 100644
+index a180612fea46ec9f7dcfe1781e985dd2e98ed513..7cb8329fc787aa6a9f877afb43dc9cd655cb0e90 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -1526,13 +1526,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
+@@ -1518,13 +1518,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 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70c
entity.setOldPosAndRot();
entity.tickCount++;
entity.totalEntityAge++; // Paper - age-like counter for all entities
-@@ -1545,13 +1539,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
+@@ -1537,13 +1531,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
for (Entity entity1 : entity.getPassengers()) {
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
}
@@ -149,7 +149,7 @@ index 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70c
private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
-index 7573c566aace4b7661c5aed6d96653472bab81bb..84808bf3311067409aad99817d3f1df2c098d83c 100644
+index fc39af434b59054260d763b994fb50bcf92b4ff3..ddc2a7fbca414b8e3c044cfe7076d2cac182b63e 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -1166,16 +1166,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
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/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/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;
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 的混淆种子."));
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/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 {
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..23967287
--- /dev/null
+++ b/leaf-server/src/main/java/org/dreeam/leaf/world/RandomTickSystem.java
@@ -0,0 +1,168 @@
+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++) {
+ final 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) {
+ int count = chunk.leaf$tickingBlocksCount();
+ if (count == 0) {
+ return;
+ }
+ OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(count));
+ 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;
+ }
+}
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) ||
diff --git a/public/image/RainYun.jpg b/public/image/RainYun.jpg
new file mode 100644
index 00000000..38e45e58
Binary files /dev/null and b/public/image/RainYun.jpg differ
diff --git a/public/readme/README_CN.md b/public/readme/README_CN.md
index 0d0a16f5..0fd85368 100644
--- a/public/readme/README_CN.md
+++ b/public/readme/README_CN.md
@@ -123,7 +123,7 @@ Leaf 根据其上游项目及其他材料,采用多种开源许可证授权,
## 🔥 特别感谢
-
+[](https://cloud.swordsman.com.cn/?i8ab42c) \
剑客云 | cloud of swordsman
如果你想找一个低价高性能、低延迟的云服务商,剑客云是个不错的选择!你可以在 [这里](https://cloud.swordsman.com.cn/?i8ab42c) 注册。
@@ -131,7 +131,15 @@ Leaf 根据其上游项目及其他材料,采用多种开源许可证授权,
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).
---
-
+[](https://www.rainyun.com/NzE2NTc1_) \
+雨云 | RainYun
+
+国际多线路选择,配套云存储 — 购买服务后七天内不满意可以申请退订,强大的技术支持团队和高在线率客服。雨云云服务器,用稳定和性价比,助力您快速上云。点击前往 [雨云](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 通过创新和智能的工具支持开源项目,用于监控和分析 Java 和 .NET 应用程序。
YourKit 是 [YourKit Java Profiler](https://www.yourkit.com/java/profiler/)、
diff --git a/scripts/upstreamCommit.sh b/scripts/upstreamCommit.sh
index 4fd006df..0f6ea255 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 "main")) # 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.6") # Update this on every version update
# Updates found
if [ -n "$purpur" ]; then