9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00
Files
Leaf/leaf-server/minecraft-patches/features/0153-Async-target-finding.patch
2025-05-19 18:07:37 +02:00

2075 lines
100 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <kaandindar21@gmail.com>
Date: Sat, 29 Mar 2025 13:40:46 +0100
Subject: [PATCH] Async target finding
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index b6af8da084c83ee38bb3ecea6a98feb0c1c74d2a..561723eeb1dd80f7fdd9aff33f6e1c4c16def0ff 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -40,8 +40,10 @@ public final class ChunkEntitySlices {
private final EntityCollectionBySection allEntities;
private final EntityCollectionBySection hardCollidingEntities;
- private final Reference2ObjectOpenHashMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
- private final Reference2ObjectOpenHashMap<EntityType<?>, EntityCollectionBySection> entitiesByType;
+ // Leaf start - Async target finding
+ private final Reference2ObjectMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
+ private final Reference2ObjectMap<EntityType<?>, EntityCollectionBySection> entitiesByType;
+ // Leaf end - Async target finding
private final EntityList entities = new EntityList();
public FullChunkStatus status;
@@ -67,9 +69,15 @@ public final class ChunkEntitySlices {
this.allEntities = new EntityCollectionBySection(this);
this.hardCollidingEntities = new EntityCollectionBySection(this);
- this.entitiesByClass = new Reference2ObjectOpenHashMap<>();
- this.entitiesByType = new Reference2ObjectOpenHashMap<>();
-
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ this.entitiesByClass = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>());
+ this.entitiesByType = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>());
+ } else {
+ this.entitiesByClass = new Reference2ObjectOpenHashMap<>();
+ this.entitiesByType = new Reference2ObjectOpenHashMap<>();
+ }
+ // Leaf end - Async target finding
this.status = status;
this.chunkData = chunkData;
}
@@ -248,14 +256,26 @@ public final class ChunkEntitySlices {
this.hardCollidingEntities.addEntity(entity, sectionIndex);
}
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ synchronized (this.entitiesByClass) {
+ for (final var entry : this.entitiesByClass.reference2ObjectEntrySet()) {
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().addEntity(entity, sectionIndex);
+ }
+ }
+ }
+ } else {
+ for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
+ this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext(); ) {
+ final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
- if (entry.getKey().isInstance(entity)) {
- entry.getValue().addEntity(entity, sectionIndex);
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().addEntity(entity, sectionIndex);
+ }
}
}
+ // Leaf end - Async target finding
EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
if (byType != null) {
@@ -282,14 +302,27 @@ public final class ChunkEntitySlices {
this.hardCollidingEntities.removeEntity(entity, sectionIndex);
}
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ synchronized (this.entitiesByClass) {
+ for (final var entry : this.entitiesByClass.reference2ObjectEntrySet()) {
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().removeEntity(entity, sectionIndex);
+ }
+ }
+ }
+ } else {
+ for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
+ this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) {
+ final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
- if (entry.getKey().isInstance(entity)) {
- entry.getValue().removeEntity(entity, sectionIndex);
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().removeEntity(entity, sectionIndex);
+ }
}
}
+ // Leaf end - Async target finding
+
final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
byType.removeEntity(entity, sectionIndex);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 24926aa7ed5c78b235659daf18b224b14beb744c..98af1ad020a003db66d7319f33d43deec315aec5 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -292,6 +292,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public gg.pufferfish.pufferfish.util.AsyncExecutor mobSpawnExecutor = new gg.pufferfish.pufferfish.util.AsyncExecutor("Leaf Async Mob Spawn Thread"); // Pufferfish - optimize mob spawning // Leaf - Fix Pufferfish and Purpur patches - Unify thread name
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // SparklyPaper - parallel world ticking
+ @Nullable public org.dreeam.leaf.async.ai.AsyncGoalThread asyncGoalThread; // Leaf - Async target finding
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1088,6 +1089,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
org.dreeam.leaf.async.AsyncPlayerDataSaving.IO_POOL.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
} catch (java.lang.InterruptedException ignored) {}
// Leaf end - Async playerdata saving
+ // Leaf start - Async target finding
+ if (this.asyncGoalThread != null) {
+ try {
+ this.asyncGoalThread.join();
+ } catch (java.lang.InterruptedException ignored) {
+ }
+ }
+ // Leaf end - Async target finding
}
public String getLocalIp() {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 33dd16a26edd2974f04d9a868d3e58e8e3060032..eb0589b203bcf72cd24bb37f2c448c23cb8d6f2b 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -255,6 +255,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.info("Using " + serverLevelTickingSemaphore.availablePermits() + " permits for parallel world ticking"); // SparklyPaper - parallel world ticking
}
// Leaf end - SparklyPaper - parallel world ticking mod (make configurable)
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ asyncGoalThread = new org.dreeam.leaf.async.ai.AsyncGoalThread(this);
+ }
+ // Leaf end - Async target finding
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
// Gale start - Pufferfish - SIMD support
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 9af7dafe03812d96aa477584d4147a68c240ab21..e6fd46b8148e050c4807abf6c8a03e4747bc0da2 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -177,7 +177,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private static final Logger LOGGER = LogUtils.getLogger();
private static final int EMPTY_TIME_NO_TICK = 300;
private static final int MAX_SCHEDULED_TICKS_PER_TICK = 65536;
- final List<ServerPlayer> players = Lists.newArrayList();
+ // Leaf start - Async target finding
+ final List<ServerPlayer> players;
+ {
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ this.players = Lists.newCopyOnWriteArrayList();
+ } else {
+ this.players = Lists.newArrayList();
+ }
+ }
+ // Leaf end - Async target finding
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
@@ -218,6 +227,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current)
public boolean hasRidableMoveEvent = false; // Purpur - Ridables
final List<ServerPlayer> realPlayers; // Leaves - skip
+ public final @Nullable org.dreeam.leaf.async.ai.AsyncGoalExecutor asyncGoalExecutor; // Leaf - Async target finding
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -335,6 +345,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);
@@ -711,6 +727,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);
+ } else {
+ this.asyncGoalExecutor = null;
+ }
+ // Leaf end - Async target finding
}
// Paper start
@@ -855,12 +878,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
@@ -1329,6 +1354,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) {
@@ -1345,6 +1371,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 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..88809afe30bb970a7de8bdfd269268800516c426 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -144,6 +144,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
private float restrictRadius = -1.0F;
public boolean aware = true; // CraftBukkit
public int ticksSinceLastInteraction; // Purpur - Entity lifespan
+ // Leaf start - Async target finding
+ public boolean tickingTarget;
+ public final org.dreeam.leaf.async.ai.Waker getGoalCtx() {
+ return tickingTarget ? this.targetSelector.ctx : this.goalSelector.ctx;
+ }
+ // Leaf end - Async target finding
protected Mob(EntityType<? extends Mob> entityType, Level level) {
super(entityType, level);
@@ -225,12 +231,22 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
}
// Paper end - Skip AI during inactive ticks for non-aware mobs
boolean isThrottled = org.dreeam.leaf.config.modules.opt.ThrottleInactiveGoalSelectorTick.enabled && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking
+ // Leaf start - Async target finding
+ boolean running = this.targetSelector.ctxState != -1 || this.goalSelector.ctxState != -1;
+ this.tickingTarget = false;
if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking
this.goalSelector.tick();
}
+ this.tickingTarget = true;
if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority
this.targetSelector.tick();
}
+ 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());
+ }
+ }
+ // Leaf end - Async target finding
}
// Paper end
@@ -914,17 +930,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;
if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
this.goalSelector.tick();
}
+ 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());
+ }
+ }
+ // Leaf end - Async target finding
this.navigation.tick();
this.customServerAiStep((ServerLevel)this.level());
diff --git a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java
index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d773403d0716f6 100644
--- 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<T extends LivingEntity> extends Goal {
@Override
public boolean canUse() {
+ // Leaf start - Async Avoid Entity Finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (!poll()) {
+ getNearestEntityAsync();
+ return false;
+ }
+ } else {
this.toAvoid = getServerLevel(this.mob)
.getNearestEntity(
this.mob.level().getEntitiesOfClass(this.avoidClass, this.mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist), livingEntity -> true),
this.avoidEntityTargeting,
this.mob,
this.mob.getX(),
- this.mob.getY(),
+ this.mob.getEyeY(), // Leaf - Async Avoid Entity Finding
this.mob.getZ()
);
+ }
+ // Leaf end - Async Avoid Entity Finding
if (this.toAvoid == null) {
return false;
} else {
@@ -91,6 +100,36 @@ public class AvoidEntityGoal<T extends LivingEntity> extends Goal {
}
}
+ // Leaf start - Async Avoid Entity Finding
+ private boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false;
+ var serverLevel = getServerLevel(this.mob);
+ if (serverLevel == null || !target.isAlive() || !this.avoidEntityTargeting.test(serverLevel, this.mob, target)) return false;
+ this.toAvoid = (T) target;
+ return true;
+ }
+
+ private void getNearestEntityAsync() {
+ final var mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final double x = mob.getX();
+ final double y = mob.getEyeY();
+ final double z = mob.getZ();
+ final var serverLevel = getServerLevel(mob);
+ final var avoidClass = this.avoidClass;
+ final var bound = mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist);
+ ctx.wake = () -> serverLevel.getNearestEntity(
+ serverLevel.getEntitiesOfClass(avoidClass, bound, livingEntity -> true),
+ avoidEntityTargeting,
+ mob,
+ x,
+ y,
+ z
+ );
+ }
+ // Leaf end - Async Avoid Entity Finding
+
@Override
public boolean canContinueToUse() {
return !this.pathNav.isDone();
diff --git a/net/minecraft/world/entity/ai/goal/BegGoal.java b/net/minecraft/world/entity/ai/goal/BegGoal.java
index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375b12aca78 100644
--- 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
+ protected boolean poll() {
+ if (!(this.wolf.getGoalCtx().result() instanceof Player target)) return false;
+ if (target == null) return false;
+ ServerLevel serverLevel = getServerLevel(this.wolf);
+ if (serverLevel == null || !target.isAlive() || !playerHoldingInteresting(target)) return false;
+ this.player = target;
+ return true;
+ }
+
+ private void findTargetAsync() {
+ final Wolf wolf = this.wolf;
+ final var ctx = wolf.getGoalCtx();
+ if (!ctx.state) return;
+ final ServerLevel serverLevel = getServerLevel(wolf);
+ final TargetingConditions begTargeting = this.begTargeting;
+ ctx.wake = () -> {
+ var player = serverLevel.getNearestPlayer(begTargeting, wolf);
+ if (player != null && playerHoldingInteresting(player)) {
+ return player;
+ }
+ return null;
+ };
+ }
+ // 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) {
+ findTargetAsync();
+ return false;
+ }
+ // Leaf end - Async Target Finding
this.player = this.level.getNearestPlayer(this.begTargeting, this.wolf);
return this.player != null && this.playerHoldingInteresting(this.player);
}
@@ -59,10 +94,10 @@ public class BegGoal extends Goal {
this.lookTime--;
}
- private boolean playerHoldingInteresting(Player player) {
+ 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
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
--- 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 {
@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
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.CatLie;
+ }
+ // Leaf end - Async search block
}
diff --git a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java
index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d35a172a3b 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 {
@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
return false;
} else {
- BlockState blockState = level.getBlockState(pos);
+ BlockState blockState = level.getBlockState(pos); // Leaf - Async search block - diff on change
return blockState.is(Blocks.CHEST)
? ChestBlockEntity.getOpenCount(level, pos) < 1
: blockState.is(Blocks.FURNACE) && blockState.getValue(FurnaceBlock.LIT)
|| blockState.is(BlockTags.BEDS, state -> state.getOptionalValue(BedBlock.PART).map(bedPart -> bedPart != BedPart.HEAD).orElse(true));
}
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.CatSit;
+ }
+ // Leaf end - Async search block
}
diff --git a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java
index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..92b6f87817aee8b277c07cf9138bf52aa20a82d6 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
+ private boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false;
+ var serverLevel = getServerLevel(this.mob);
+ return serverLevel != null && target.isAlive() && !target.isSpectator() && (Mth.abs(target.xxa) > 0.0F || Mth.abs(target.zza) > 0.0F);
+ }
+
+ private void findTargetAsync() {
+ final PathfinderMob mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final var bound = mob.getBoundingBox().inflate(5.0);
+ final var serverLevel = getServerLevel(mob);
+ ctx.wake = () -> {
+ List<AbstractBoat> entitiesOfClass = serverLevel.getEntitiesOfClass(AbstractBoat.class, bound);
+ for (AbstractBoat abstractBoat : entitiesOfClass) {
+ Entity controllingPassenger = abstractBoat.getControllingPassenger();
+ if (controllingPassenger instanceof Player player
+ && (Mth.abs(player.xxa) > 0.0F || Mth.abs(player.zza) > 0.0F)) {
+ return player;
+
+ }
+ }
+ return null;
+ };
+ }
+ // Leaf end - Async Target Finding
@Override
public boolean canUse() {
+ // Leaf start - Async Target Finding
+ if (poll()) {
+ return true;
+ }
+ if (this.following != null && (Mth.abs(this.following.xxa) > 0.0F || Mth.abs(this.following.zza) > 0.0F)) {
+ return true;
+ }
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ findTargetAsync();
+ return false;
+ }
+ // Leaf end - Async Target Finding
List<AbstractBoat> entitiesOfClass = this.mob.level().getEntitiesOfClass(AbstractBoat.class, this.mob.getBoundingBox().inflate(5.0));
boolean flag = false;
@@ -37,7 +76,7 @@ public class FollowBoatGoal extends Goal {
}
}
- 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
}
@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
--- 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
+ if (poll()) {
+ return true;
+ }
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ getFollowingMobAsync();
+ return false;
+ }
+ // Leaf end - Async Follow Mob Finding
List<Mob> entitiesOfClass = this.mob.level().getEntitiesOfClass(Mob.class, this.mob.getBoundingBox().inflate(this.areaSize), this.followPredicate);
if (!entitiesOfClass.isEmpty()) {
for (Mob mob : entitiesOfClass) {
@@ -51,6 +60,36 @@ public class FollowMobGoal extends Goal {
return false;
}
+ // Leaf start - Async Follow Mob Finding
+ private boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof Mob target)) return false;
+ var serverLevel = getServerLevel(this.mob);
+ if (serverLevel == null || !target.isAlive() || target.isInvisible()) return false;
+ this.followingMob = target;
+ return true;
+ }
+
+ private void getFollowingMobAsync() {
+ final var mob = this.mob;
+ final var ctx = this.mob.getGoalCtx();
+ if (!ctx.state) return;
+ final var serverLevel = getServerLevel(mob);
+ final var bound = this.mob.getBoundingBox().inflate(this.areaSize);
+ final var followPredicate = this.followPredicate;
+ ctx.wake = () -> {
+ List<Mob> entitiesOfClass = serverLevel.getEntitiesOfClass(Mob.class, bound, followPredicate);
+ if (!entitiesOfClass.isEmpty()) {
+ for (final Mob follow : entitiesOfClass) {
+ if (!follow.isInvisible()) {
+ return follow;
+ }
+ }
+ }
+ return null;
+ };
+ }
+ // Leaf end - Async Follow Mob 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
--- 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
+ protected boolean poll() {
+ if (!(this.animal.getGoalCtx().result() instanceof Animal target)) return false;
+ var serverLevel = getServerLevel(animal);
+ if (serverLevel == null || !target.isAlive() || animal.distanceToSqr(target) < 9.0) return false;
+ this.parent = animal;
+ return true;
+ }
+
+ private void findTargetAsync() {
+ final Animal animal = this.animal;
+ final var ctx = animal.getGoalCtx();
+ if (!ctx.state) return;
+ final var targetType = animal.getClass();
+ final var bound = animal.getBoundingBox().inflate(8.0, 4.0, 8.0);
+ final var serverLevel = getServerLevel(animal);
+ final var pos = animal.position();
+ ctx.wake = () -> {
+ List<? extends Animal> entitiesOfClass = serverLevel.getEntitiesOfClass(targetType, bound);
+ Animal target = null;
+ double d = Double.MAX_VALUE;
+
+ for (Animal animal1 : entitiesOfClass) {
+ if (animal1.getAge() >= 0) {
+ double d1 = animal1.distanceToSqr(pos);
+ if (!(d1 > d)) {
+ d = d1;
+ target = animal1;
+ }
+ }
+ }
+ return target;
+ };
+ }
+ // Leaf end - Async Target Finding
+
@Override
public boolean canUse() {
if (this.animal.getAge() >= 0) {
return false;
} else {
+ // Leaf start - Async Target Finding
+ if (poll()) {
+ return true;
+ }
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ findTargetAsync();
+ return false;
+ }
+ // 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));
@@ -43,6 +88,7 @@ public class FollowParentGoal extends Goal {
if (animal == null) {
return false;
} else if (d < 9.0) {
+ // Leaf - Async Target Finding - diff on change
return false;
} else {
this.parent = animal;
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb506310de8461 100644
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -26,13 +26,23 @@ public class GoalSelector {
private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from GoalSelector
private int curRate; // Paper - EAR 2
+ // Leaf start - Async target finding
+ private boolean availableGoalsDirty = true;
+ private WrappedGoal @org.jetbrains.annotations.Nullable[] ctxGoals = null;
+ private int ctxIndex = 0;
+ public int ctxState = -1;
+ public final org.dreeam.leaf.async.ai.Waker ctx = new org.dreeam.leaf.async.ai.Waker();
+ // Leaf end - Async target finding
+
public void addGoal(int priority, Goal goal) {
this.availableGoals.add(new WrappedGoal(priority, goal));
+ availableGoalsDirty = true; // Leaf - Async target finding
}
@VisibleForTesting
public void removeAllGoals(Predicate<Goal> filter) {
this.availableGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal()));
+ availableGoalsDirty = true; // Leaf - Async target finding
}
// Paper start - EAR 2
@@ -63,18 +73,19 @@ public class GoalSelector {
}
this.availableGoals.removeIf(wrappedGoal1 -> wrappedGoal1.getGoal() == goal);
+ availableGoalsDirty = true; // Leaf - Async target finding
}
// Paper start - Perf: optimize goal types
private static boolean goalContainsAnyFlags(WrappedGoal goal, ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> flags) {
- return goal.getFlags().hasCommonElements(flags);
+ return goal.getFlags().hasCommonElements(flags); // Leaf - Async target finding - inline diff
}
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> flag) {
long flagIterator = goal.getFlags().getBackingSet();
int wrappedGoalSize = goal.getFlags().size();
for (int i = 0; i < wrappedGoalSize; ++i) {
- final Goal.Flag flag1 = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
+ final Goal.Flag flag1 = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; // Leaf - Async target finding - inline diff
flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
// Paper end - Perf: optimize goal types
if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) {
@@ -85,7 +96,131 @@ public class GoalSelector {
return true;
}
+ // Leaf start - Async target finding
+ public final boolean poll() {
+ if (this.ctxGoals == null || ctx.wake != null) {
+ return false;
+ }
+ if (ctxState == 0) {
+ while (ctxIndex < this.ctxGoals.length) {
+ WrappedGoal goal = this.ctxGoals[ctxIndex];
+ // entity tempt
+ if (goal.isRunning() && (goalContainsAnyFlags(goal, this.goalTypes) || !goal.canContinueToUse())) {
+ ctx.state = false;
+ if (ctx.wake != null) {
+ return true;
+ }
+ goal.stop();
+ }
+
+ ctxIndex++;
+ ctx.state = true;
+ }
+
+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning());
+
+ ctxIndex = 0;
+ ctx.state = true;
+ ctxState = 1;
+ }
+ if (ctxState == 1) {
+ while (ctxIndex < this.ctxGoals.length) {
+ WrappedGoal goal = this.ctxGoals[ctxIndex];
+ var flags = goal.getFlags();
+ // entity and block
+ if (!goal.isRunning() && !flags.hasCommonElements(this.goalTypes)) {
+ // inline
+ boolean result = true;
+ long flagIterator1 = flags.getBackingSet();
+ int wrappedGoalSize1 = flags.size();
+ for (int i1 = 0; i1 < wrappedGoalSize1; ++i1) {
+ final Goal.Flag flag1 = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator1)];
+ flagIterator1 ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator1);
+ if (!this.lockedFlags.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) {
+ result = false;
+ break;
+ }
+ }
+ if (result) {
+ if (goal.canUse()) {
+ long flagIterator = flags.getBackingSet();
+ int wrappedGoalSize = flags.size();
+ for (int i = 0; i < wrappedGoalSize; ++i) {
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
+ WrappedGoal wrappedGoal1 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
+ wrappedGoal1.stop();
+ this.lockedFlags.put(flag, goal);
+ }
+
+ goal.start();
+ }
+ ctx.state = false;
+ if (ctx.wake != null) {
+ return true;
+ }
+ }
+ }
+ // entity alert other
+ 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();
+ default -> {}
+ }
+ }
+ ctxIndex++;
+ ctx.state = true;
+ }
+
+ ctxIndex = 0;
+ ctx.state = true;
+ ctxState = 2;
+ }
+ if (ctxState == 2) {
+ while (ctxIndex < this.ctxGoals.length) {
+ WrappedGoal goal = this.ctxGoals[ctxIndex];
+ if (goal.isRunning()) {
+ goal.tick();
+ }
+ ctxIndex++;
+ }
+
+ ctxState = -1;
+ ctxIndex = 0;
+ ctx.state = true;
+ }
+ if (ctxState == 3) {
+ while (ctxIndex < this.ctxGoals.length) {
+ WrappedGoal goal = this.ctxGoals[ctxIndex];
+ if (goal.isRunning() && goal.requiresUpdateEveryTick()) {
+ goal.tick();
+ }
+ ctxIndex++;
+ }
+
+ ctxState = -1;
+ ctxIndex = 0;
+ ctx.state = true;
+ }
+ return false;
+ }
+ // Leaf end - Async target finding
+
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) {
+ this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]);
+ availableGoalsDirty = false;
+ }
+ ctxState = 0;
+ }
+ return;
+ }
+ // Leaf end - Async target finding
+
for (WrappedGoal wrappedGoal : this.availableGoals) {
if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
wrappedGoal.stop();
@@ -116,6 +251,18 @@ public class GoalSelector {
}
public void tickRunningGoals(boolean tickAllRunning) {
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ if (ctxState == -1) {
+ if (availableGoalsDirty || this.ctxGoals == null) {
+ this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]);
+ availableGoalsDirty = false;
+ }
+ ctxState = tickAllRunning ? 2 : 3;
+ }
+ return;
+ }
+ // Leaf end - Async target finding
for (WrappedGoal wrappedGoal : this.availableGoals) {
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
--- 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
+ private @javax.annotation.Nullable Llama poll() {
+ if (!(this.llama.getGoalCtx().result() instanceof Llama target)) return null;
+ var serverLevel = getServerLevel(this.llama);
+ if (serverLevel == null || !target.isAlive()) return null;
+ return target;
+ }
+
+ private void findTargetAsync() {
+ final Llama llama = this.llama;
+ final var ctx = llama.getGoalCtx();
+ if (!ctx.state) return;
+ final var bound = llama.getBoundingBox().inflate(9.0, 4.0, 9.0);
+ final var serverLevel = getServerLevel(llama);
+ final var pos = llama.position();
+ ctx.wake = () -> {
+ List<Entity> entities = serverLevel.getEntities(llama, bound, entity1 -> {
+ EntityType<?> type = entity1.getType();
+ return type == EntityType.LLAMA || type == EntityType.TRADER_LLAMA;
+ });
+ Llama target = null;
+ double d = Double.MAX_VALUE;
+
+ for (Entity entity : entities) {
+ Llama llama1 = (Llama) entity;
+ if (llama1.inCaravan() && !llama1.hasCaravanTail()) {
+ double d1 = llama1.distanceToSqr(pos);
+ if (!(d1 > d)) {
+ d = d1;
+ target = llama1;
+ }
+ }
+ }
+
+ if (target == null) {
+ for (Entity entityx : entities) {
+ Llama llama1 = (Llama) entityx;
+ if (llama1.isLeashed() && !llama1.hasCaravanTail()) {
+ double d1 = llama1.distanceToSqr(pos);
+ if (!(d1 > d)) {
+ d = d1;
+ target = llama1;
+ }
+ }
+ }
+ }
+ return target;
+ };
+ }
+ // 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
+ Llama llama = poll();
+ double d = Double.MAX_VALUE;
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ if (llama == null) {
+ findTargetAsync();
+ return false;
+ } else {
+ d = this.llama.distanceToSqr(llama);
+ }
+ } else {
+ // Leaf end - Async Target Finding
List<Entity> 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
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
double d1 = this.llama.distanceToSqr(llama1);
if (!(d1 > d)) {
d = d1;
@@ -45,7 +108,7 @@ public class LlamaFollowCaravanGoal extends Goal {
if (llama == null) {
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
double d1 = this.llama.distanceToSqr(llama1);
if (!(d1 > d)) {
d = d1;
@@ -54,6 +117,7 @@ public class LlamaFollowCaravanGoal extends Goal {
}
}
}
+ } // 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
--- 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
+ if (poll()) {
+ return true;
+ }
if (this.mob.getRandom().nextFloat() >= this.probability) {
return false;
+ }
+ if (this.mob.getTarget() != null) {
+ this.lookAt = this.mob.getTarget();
+ }
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ getLookAsync();
+ return false;
+ }
+ ServerLevel serverLevel = getServerLevel(this.mob);
+ if (this.lookAtType == Player.class) {
+ this.lookAt = serverLevel.getNearestPlayer(this.lookAtContext, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
} else {
- if (this.mob.getTarget() != null) {
- this.lookAt = this.mob.getTarget();
- }
+ this.lookAt = serverLevel.getNearestEntity(
+ this.mob
+ .level()
+ .getEntitiesOfClass(this.lookAtType, this.mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance), livingEntity -> true),
+ this.lookAtContext,
+ this.mob,
+ this.mob.getX(),
+ this.mob.getEyeY(),
+ this.mob.getZ()
+ );
+ }
- ServerLevel serverLevel = getServerLevel(this.mob);
- if (this.lookAtType == Player.class) {
- this.lookAt = serverLevel.getNearestPlayer(this.lookAtContext, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
+ return this.lookAt != null;
+ }
+
+ protected boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false;
+ if (this.mob.getTarget() != null) {
+ this.lookAt = this.mob.getTarget();
+ return true;
+ }
+ ServerLevel serverLevel = getServerLevel(this.mob);
+ if (!target.isAlive() || !this.lookAtContext.test(serverLevel, this.mob, target)) return false;
+ this.lookAt = target;
+ return true;
+ }
+
+ protected void getLookAsync() {
+ final var mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final double x = mob.getX();
+ final double y = mob.getEyeY();
+ final double z = mob.getZ();
+ final var serverLevel = getServerLevel(mob);
+ final var bound = mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance);
+ final var lookAtContext = this.lookAtContext;
+ final var lookAtType = this.lookAtType;
+ ctx.wake = () -> {
+ if (lookAtType == Player.class) {
+ return serverLevel.getNearestPlayer(lookAtContext, mob, x, y, z);
} else {
- this.lookAt = serverLevel.getNearestEntity(
- this.mob
- .level()
- .getEntitiesOfClass(this.lookAtType, this.mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance), livingEntity -> true),
- this.lookAtContext,
- this.mob,
- this.mob.getX(),
- this.mob.getEyeY(),
- this.mob.getZ()
+ return serverLevel.getNearestEntity(
+ serverLevel
+ .getEntitiesOfClass(lookAtType, bound, livingEntity -> true),
+ lookAtContext,
+ mob,
+ x,
+ y,
+ z
);
}
-
- return this.lookAt != null;
- }
+ };
}
+ // Leaf end - Async look finding
@Override
public boolean canContinueToUse() {
diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e7c93afca 100644
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
@@ -41,8 +41,60 @@ public abstract class MoveToBlockGoal extends Goal {
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP));
}
+ // Leaf start - Async search block
+ protected boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof BlockPos blockPos1)) return false;
+ if (!this.mob.level().hasChunkAt(blockPos1)
+ || !this.mob.isWithinRestriction(blockPos1)
+ || !this.isValidTarget(this.mob.level(), blockPos1)) {
+ return false;
+ }
+ this.blockPos = blockPos1;
+ this.mob.movingTarget = blockPos1 == BlockPos.ZERO ? null : blockPos1;
+ return true;
+ }
+
+ protected void getBlockAsync() {
+ final var mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final var serverLevel = getServerLevel(mob);
+ final TypeToCheck ty = this.typeToCheck();
+ final net.minecraft.world.level.block.Block toRemove;
+ if (this instanceof RemoveBlockGoal removeBlockGoal) {
+ toRemove = removeBlockGoal.blockToRemove;
+ } else {
+ toRemove = null;
+ }
+ final int verticalSearchStart = this.verticalSearchStart;
+ final int searchRange = this.searchRange;
+ final int verticalSearchRange = this.verticalSearchRange;
+ final BlockPos blockPos = mob.blockPosition();
+ final float restrictRadius = mob.getRestrictRadius();
+ final BlockPos restrictCenter = mob.getRestrictCenter();
+ ctx.wake = () -> findNearestBlockAsync(ty, toRemove, mob, serverLevel, verticalSearchStart, searchRange, verticalSearchRange, blockPos, restrictRadius, restrictCenter);
+ }
+
+ protected enum TypeToCheck {
+ CatLie,
+ CatSit,
+ Drowned,
+ FoxEat,
+ RaidGarden,
+ RemoveBlock,
+ Strider,
+ TurtleToWater,
+ TurtleLay,
+ }
+ // Leaf end - Async search block
+
@Override
public boolean canUse() {
+ // Leaf start - Async search block
+ if (poll()) {
+ return true;
+ }
+ // Leaf end - Async search block
if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
@@ -109,6 +161,12 @@ public abstract class MoveToBlockGoal extends Goal {
}
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 {
return false;
}
+ // Leaf start - Async search block
+ protected static @javax.annotation.Nullable BlockPos findNearestBlockAsync(
+ final TypeToCheck ty,
+ @org.jetbrains.annotations.Nullable final net.minecraft.world.level.block.Block toRemove,
+ final PathfinderMob mob,
+ final net.minecraft.server.level.ServerLevel serverLevel,
+ final int verticalSearchStart,
+ final int searchRange,
+ final int verticalSearchRange,
+ final BlockPos blockPos,
+ final float restrictRadius,
+ final BlockPos restrictCenter
+ ) {
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+ for (int i2 = verticalSearchStart; i2 <= verticalSearchRange; i2 = i2 > 0 ? -i2 : 1 - i2) {
+ for (int i3 = 0; i3 < searchRange; i3++) {
+ for (int i4 = 0; i4 <= i3; i4 = i4 > 0 ? -i4 : 1 - i4) {
+ 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 (isWithinRestriction(restrictRadius, restrictCenter, mutableBlockPos)
+ && isValidTargetAsync(ty, toRemove, mob, serverLevel, mutableBlockPos)) {
+ return mutableBlockPos.immutable();
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean isWithinRestriction(float restrictRadius, BlockPos restrictCenter, BlockPos pos) {
+ return restrictRadius == -1.0F || restrictCenter.distSqr(pos) < restrictRadius * restrictRadius;
+ }
+ // Leaf end - Async search block
+
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
+
+ // Leaf start - Async search block
+ protected abstract TypeToCheck typeToCheck();
+
+ private static boolean isValidTargetAsync(
+ TypeToCheck type,
+ @org.jetbrains.annotations.Nullable net.minecraft.world.level.block.Block blockToRemoveTy,
+ PathfinderMob mob,
+ LevelReader level,
+ BlockPos pos
+ ) {
+ switch (type) {
+ case CatLie -> {
+ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(net.minecraft.tags.BlockTags.BEDS);
+ }
+ case CatSit -> {
+ if (!level.isEmptyBlock(pos.above())) {
+ return false;
+ } else {
+ var blockState = level.getBlockState(pos);
+ return blockState.is(net.minecraft.world.level.block.Blocks.CHEST)
+ ? net.minecraft.world.level.block.entity.ChestBlockEntity.getOpenCount(level, pos) < 1
+ : blockState.is(net.minecraft.world.level.block.Blocks.FURNACE) && blockState.getValue(net.minecraft.world.level.block.FurnaceBlock.LIT)
+ || blockState.is(net.minecraft.tags.BlockTags.BEDS, state -> state.getOptionalValue(net.minecraft.world.level.block.BedBlock.PART).map(bedPart -> bedPart != net.minecraft.world.level.block.state.properties.BedPart.HEAD).orElse(true));
+ }
+ }
+ case Drowned -> {
+ BlockPos blockPos = pos.above();
+ return level.isEmptyBlock(blockPos) && level.isEmptyBlock(blockPos.above()) && level.getBlockState(pos).entityCanStandOn(level, pos, mob);
+ }
+ case FoxEat -> {
+ var blockState = level.getBlockState(pos);
+ return blockState.is(net.minecraft.world.level.block.Blocks.SWEET_BERRY_BUSH) && blockState.getValue(net.minecraft.world.level.block.SweetBerryBushBlock.AGE) >= 2 || net.minecraft.world.level.block.CaveVines.hasGlowBerries(blockState);
+ }
+ case RaidGarden -> {
+ var blockState = level.getBlockState(pos);
+ if (blockState.is(net.minecraft.world.level.block.Blocks.FARMLAND)) {
+ blockState = level.getBlockState(pos.above());
+ return blockState.getBlock() instanceof net.minecraft.world.level.block.CarrotBlock carrot && carrot.isMaxAge(blockState);
+ } else {
+ return false;
+ }
+
+ }
+ case RemoveBlock -> {
+ var chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks
+ return chunk != null
+ && chunk.getBlockState(pos).is(blockToRemoveTy)
+ && chunk.getBlockState(pos.above()).isAir()
+ && chunk.getBlockState(pos.above(2)).isAir();
+ }
+ case Strider -> {
+ return level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.LAVA) && level.getBlockState(pos.above()).isPathfindable(net.minecraft.world.level.pathfinder.PathComputationType.LAND);
+ }
+ case TurtleToWater -> {
+ return level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.WATER);
+ }
+ case TurtleLay -> {
+ return level.isEmptyBlock(pos.above()) && net.minecraft.world.level.block.TurtleEggBlock.isSand(level, pos);
+ }
+ case null -> throw new IllegalStateException();
+ }
+ // Leaf end - Async search block
+ }
}
diff --git a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java
index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80691ac1bc 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
if (!this.golem.level().isDay()) {
return false;
- } else if (this.golem.getRandom().nextInt(8000) != 0) {
+ }
+ if (poll()) {
+ return true;
+ }
+ if (this.golem.getRandom().nextInt(8000) != 0) {
return false;
+ }
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ getVillagerAsync();
+ return false;
+ // Leaf end - Async offer flower finding
} else {
this.villager = getServerLevel(this.golem)
.getNearestEntity(
@@ -38,6 +48,36 @@ public class OfferFlowerGoal extends Goal {
}
}
+
+ // Leaf start - Async look finding
+ protected boolean poll() {
+ if (!(this.golem.getGoalCtx().result() instanceof Villager target)) return false;
+ var serverLevel = getServerLevel(this.golem);
+ if (!target.isAlive() || !OFFER_TARGER_CONTEXT.test(serverLevel, this.golem, target)) return false;
+ this.villager = target;
+ return true;
+ }
+
+ protected void getVillagerAsync() {
+ final var golem = this.golem;
+ final var ctx = golem.getGoalCtx();
+ if (!ctx.state) return;
+ final double x = golem.getX();
+ final double y = golem.getEyeY();
+ final double z = golem.getZ();
+ final var serverLevel = getServerLevel(golem);
+ final var bound = golem.getBoundingBox().inflate(6.0, 2.0, 6.0);
+ ctx.wake = () -> serverLevel.getNearestEntity(
+ serverLevel.getEntitiesOfClass(Villager.class, bound, livingEntity -> true),
+ OFFER_TARGER_CONTEXT,
+ golem,
+ x,
+ y,
+ z
+ );
+ }
+ // Leaf end - Async look finding
+
@Override
public boolean canContinueToUse() {
return this.tick > 0;
diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700b4c8a02d 100644
--- 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 {
public boolean canUse() {
if (!getServerLevel(this.removerMob).purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
return false;
- } else if (this.nextStartTick > 0) {
+ }
+ // Leaf start - async search block
+ if (poll()) {
+ this.nextStartTick = reducedTickDelay(20);
+ return true;
+ }
+ // Leaf end - async search block
+ if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
} else if (this.findNearestBlock()) {
@@ -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.above()).isAir()
&& chunk.getBlockState(pos.above(2)).isAir();
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.RemoveBlock;
+ }
+ // Leaf end - Async search block
}
diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java
index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50e9e62b34 100644
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
@@ -36,12 +36,51 @@ public class TemptGoal extends Goal {
this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity));
}
+ // Leaf start - Async Tempt Finding
+ private boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false;
+ var serverLevel = getServerLevel(this.mob);
+ if (!target.isAlive() || !this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)).test(serverLevel, this.mob, target)) return false;
+ this.player = target;
+ return true;
+ }
+
+ private void getNearestPlayerAsync() {
+ final var mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final var serverLevel = getServerLevel(mob);
+ final var conditions = this.targetingConditions
+ .range(mob.getAttributeValue(Attributes.TEMPT_RANGE))
+ .copy();
+ ctx.wake = () -> serverLevel.getNearestPlayer(conditions, mob);
+ }
+ // Leaf end - Async Tempt Finding
@Override
public boolean canUse() {
if (this.calmDown > 0) {
this.calmDown--;
return false;
} else {
+ // Leaf start - Async Tempt 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 {
+ getNearestPlayerAsync();
+ return false;
+ }
+ }
+ // Leaf end - Async Tempt Finding
this.player = getServerLevel(this.mob)
.getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
// CraftBukkit start
diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..c9750ad322ddaa9c457f0e652d87c7abf8559358 100644
--- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
@@ -16,7 +16,7 @@ public class DefendVillageTargetGoal extends TargetGoal {
private final IronGolem golem;
@Nullable
private LivingEntity potentialTarget;
- private final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0);
+ private static final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); // Leaf - Async Target Finding - static
public DefendVillageTargetGoal(IronGolem golem) {
super(golem, false, true);
@@ -24,8 +24,49 @@ public class DefendVillageTargetGoal extends TargetGoal {
this.setFlags(EnumSet.of(Goal.Flag.TARGET));
}
+ // Leaf start - Async Target Finding
+ 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;
+ }
+
+ private void findTargetAsync() {
+ final IronGolem mob = this.golem;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ AABB bound = this.golem.getBoundingBox().inflate(10.0, 8.0, 10.0);
+ final ServerLevel serverLevel = getServerLevel(mob);
+ ctx.wake = () -> {
+ List<Villager> nearbyEntities = serverLevel.getNearbyEntities(Villager.class, attackTargeting, mob, bound);
+ List<Player> nearbyPlayers = serverLevel.getNearbyPlayers(attackTargeting, mob, bound);
+ for (Villager villager : nearbyEntities) {
+ for (Player player : nearbyPlayers) {
+ int playerReputation = villager.getPlayerReputation(player);
+ if (playerReputation <= -100) {
+ return player;
+ }
+ }
+ }
+ return null;
+ };
+ }
+ // 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
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);
@@ -43,7 +84,7 @@ public class DefendVillageTargetGoal extends TargetGoal {
}
return this.potentialTarget != null
- && (!(this.potentialTarget instanceof Player) || !this.potentialTarget.isSpectator() && !((Player)this.potentialTarget).isCreative());
+ && (!(this.potentialTarget instanceof Player) || !this.potentialTarget.isSpectator() && !((Player)this.potentialTarget).isCreative()); // Leaf - Async target finding - diff on change
}
@Override
diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617aa32c3cc 100644
--- 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 {
protected void alertOthers() {
double followDistance = this.getFollowDistance();
AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followDistance, 10.0, followDistance);
+
+ // Leaf start - Async alert other
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) {
+ final var self = this.mob;
+ final var ctx = self.getGoalCtx();
+ if (!ctx.state) return;
+ final var serverLevel = getServerLevel(self);
+ final var toIgnoreAlert = this.toIgnoreAlert;
+ ctx.wake = () -> {
+ var toAlert = new java.util.ArrayList<Mob>();
+ List<? extends Mob> entitiesOfClass = serverLevel
+ .getEntitiesOfClass(self.getClass(), aabb, EntitySelector.NO_SPECTATORS);
+ for (Mob mob : entitiesOfClass) {
+ if (self == mob
+ || mob.getTarget() != null
+ || (self instanceof TamableAnimal && ((TamableAnimal) self).getOwner() != ((TamableAnimal) mob).getOwner())
+ || mob.isAlliedTo(self.getLastHurtByMob())) {
+ continue;
+ }
+ if (toIgnoreAlert == null) {
+ toAlert.add(mob);
+ continue;
+ }
+ boolean flag = false;
+ for (Class<?> clazz : toIgnoreAlert) {
+ if (mob.getClass() == clazz) {
+ flag = true;
+ break;
+ }
+ }
+ if (!flag) {
+ toAlert.add(mob);
+ }
+ }
+ return toAlert;
+ };
+ return;
+ }
+ // Leaf end - Async alert other
+
List<? extends Mob> entitiesOfClass = this.mob
.level()
.getEntitiesOfClass((Class<? extends Mob>)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS);
@@ -87,7 +127,7 @@ public class HurtByTargetGoal extends TargetGoal {
mob = (Mob)var5.next();
if (this.mob != mob
- && mob.getTarget() == null
+ && mob.getTarget() == null // Leaf - Async alert other - diff on change
&& (!(this.mob instanceof TamableAnimal) || ((TamableAnimal)this.mob).getOwner() == ((TamableAnimal)mob).getOwner())
&& !mob.isAlliedTo(this.mob.getLastHurtByMob())) {
if (this.toIgnoreAlert == null) {
@@ -96,7 +136,7 @@ public class HurtByTargetGoal extends TargetGoal {
boolean flag = false;
- for (Class<?> clazz : this.toIgnoreAlert) {
+ for (Class<?> clazz : this.toIgnoreAlert) { // Leaf - Async alert other - diff on change
if (mob.getClass() == clazz) {
flag = true;
break;
@@ -113,6 +153,36 @@ public class HurtByTargetGoal extends TargetGoal {
}
}
+ // Leaf start - Async alert other
+ public void poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof List toAlert)) return;
+ LivingEntity lastHurtByMob = this.mob.getLastHurtByMob();
+ if (lastHurtByMob.getType() == EntityType.PLAYER && getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) {
+ return;
+ }
+ for (Class<?> clazz : this.toIgnoreDamage) {
+ if (clazz.isAssignableFrom(lastHurtByMob.getClass())) {
+ return;
+ }
+ }
+ if (this.mob.getTarget() == null) {
+ return;
+ }
+ if (!canContinueToUse()) {
+ return;
+ }
+ if (!this.canAttack(lastHurtByMob, HURT_BY_TARGETING)) {
+ return;
+ }
+ for (var obj : toAlert) {
+ Mob mob = (Mob) obj;
+ if (mob.getTarget() == null) {
+ alertOther(mob, lastHurtByMob);
+ }
+ }
+ }
+ // Leaf end - Async alert other
+
protected void alertOther(Mob mob, LivingEntity target) {
mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason
}
diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
index 85eae0a14f7a417dfd8c911079d05354a98e5834..f59d5c9be0eb10f5b5192442e1850900d71a31e9 100644
--- 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<T extends LivingEntity> extends TargetG
this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector);
}
+ // 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() || !this.getTargetConditions().test(serverLevel, this.mob, target)) return false;
+ this.target = target;
+ return true;
+ }
+
+ private void findTargetAsync() {
+ final Mob mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final double x = mob.getX();
+ final double y = mob.getEyeY();
+ final double z = mob.getZ();
+ final TargetingConditions targetConditions = this.getTargetConditions().copy();
+ final Class<T> targetType = this.targetType;
+ final AABB targetSearch = getTargetSearchArea(this.getFollowDistance());
+ final ServerLevel serverLevel = getServerLevel(mob);
+ ctx.wake = () -> {
+ if (targetType != Player.class && targetType != ServerPlayer.class) {
+ return serverLevel.getNearestEntity(mob.level().getEntitiesOfClass(targetType, targetSearch, entity -> entity != null && entity != mob && entity.isAlive()), targetConditions, mob, x, y, z);
+ } else {
+ return serverLevel.getNearestPlayer(targetConditions, mob, x, y, z);
+ }
+ };
+ }
+ // Leaf end - Async Target Finding
+
@Override
public boolean canUse() {
+ // Leaf start - Async target finding
+ if (poll()) {
+ return true;
+ }
+ // Leaf end - Async target finding
if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
return false;
} else {
@@ -57,6 +92,15 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> 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
--- 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<T extends LivingEntity> extends Nea
@Override
public boolean canUse() {
- if (this.cooldown > 0 || !this.mob.getRandom().nextBoolean()) {
+ // Leaf start - Async target finding
+ if (this.cooldown > 0) {
+ return false;
+ }
+ if (poll()) {
+ return ((Raider) this.mob).hasActiveRaid();
+ }
+ if (/*this.cooldown > 0 || */ !this.mob.getRandom().nextBoolean()) {
+ // Leaf end - Async target finding
return false;
} else if (!((Raider)this.mob).hasActiveRaid()) {
return false;
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
+++ b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java
@@ -20,6 +20,15 @@ public class NonTameRandomTargetGoal<T extends LivingEntity> extends NearestAtta
@Override
public boolean canContinueToUse() {
- return this.targetConditions != null ? this.targetConditions.test(getServerLevel(this.mob), this.mob, this.target) : super.canContinueToUse();
+ // Leaf start - Async target finding
+ if (this.target == null || !this.target.isAlive() || this.target.isRemoved()) {
+ return false;
+ }
+ var serverLevel = getServerLevel(this.mob);
+ if (serverLevel == null) {
+ return false;
+ }
+ return this.getTargetConditions().test(serverLevel, this.mob, this.target) && super.canContinueToUse();
+ // Leaf end - Async target finding
}
}
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
--- 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<T extends Mob & NeutralMob> extends G
this.lastHurtByPlayerTimestamp = this.mob.getLastHurtByMobTimestamp();
this.mob.forgetCurrentTargetAndRefreshUniversalAnger();
if (this.alertOthersOfSameType) {
+ // Leaf start - Async alert other
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) {
+ final var mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
+ final var serverLevel = getServerLevel(mob);
+ final double followRange = this.mob.getAttributeValue(Attributes.FOLLOW_RANGE);
+ final AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followRange, 10.0, followRange);
+ ctx.wake = () -> {
+ var entities = serverLevel.getEntitiesOfClass(mob.getClass(), aabb, EntitySelector.NO_SPECTATORS);
+ List<NeutralMob> toStop = new java.util.ArrayList<>(entities.size());
+ for (Mob entity : entities) {
+ if (entity != mob) {
+ toStop.add((NeutralMob) entity);
+ }
+ }
+ return toStop;
+ };
+ return;
+ }
+ // Leaf end - Async alert other
this.getNearbyMobsOfSameType()
.stream()
.filter(mob -> mob != this.mob)
@@ -47,7 +68,19 @@ public class ResetUniversalAngerTargetGoal<T extends Mob & NeutralMob> extends G
super.start();
}
+ // Leaf start - Async alert other
+ public void poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof List toStop)) return;
+ for (var neutralMob : toStop) {
+ if (EntitySelector.NO_SPECTATORS.test((net.minecraft.world.entity.Entity) neutralMob)) {
+ ((NeutralMob) neutralMob).forgetCurrentTargetAndRefreshUniversalAnger();
+ }
+ }
+ }
+ // Leaf end - Async alert other
+
private List<? extends Mob> getNearbyMobsOfSameType() {
+ // Leaf - Async alert other - 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);
diff --git a/net/minecraft/world/entity/ai/sensing/Sensing.java b/net/minecraft/world/entity/ai/sensing/Sensing.java
index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..6fa0b8defbd1d06b3bf5d9b32ffd08f32c1fb707 100644
--- a/net/minecraft/world/entity/ai/sensing/Sensing.java
+++ b/net/minecraft/world/entity/ai/sensing/Sensing.java
@@ -33,6 +33,17 @@ public class Sensing {
}
public void tick() {
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ synchronized (this) {
+ tickInternal();
+ }
+ } else {
+ tickInternal();
+ }
+ }
+ private void tickInternal() {
+ // Leaf end - Async target finding
if (this.expiring == null) { // Gale - Petal - reduce line of sight updates
this.seen.clear();
// Gale start - Petal - reduce line of sight updates
@@ -63,6 +74,17 @@ public class Sensing {
}
public boolean hasLineOfSight(Entity entity) {
+ // Leaf start - Async target finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ synchronized (this) {
+ return hasLineOfSightInternal(entity);
+ }
+ } else {
+ return hasLineOfSightInternal(entity);
+ }
+ }
+ private boolean hasLineOfSightInternal(Entity entity) {
+ // Leaf end - Async target finding
int id = entity.getId();
// Gale start - Petal - reduce line of sight cache lookups - merge sets
int cached = this.seen.get(id);
diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
index 90452f0945e761077608692877677f522d38bccd..54044ff16e0c2963b2220e4fb4932fe0802aa178 100644
--- a/net/minecraft/world/entity/animal/Fox.java
+++ b/net/minecraft/world/entity/animal/Fox.java
@@ -849,13 +849,18 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
return false;
} else {
ServerLevel serverLevel = getServerLevel(Fox.this.level());
+ // Leaf start - Async target finding
+ if (serverLevel == null) {
+ return false;
+ }
+ // Leaf end - Async target finding
for (UUID uuid : Fox.this.getTrustedUUIDs()) {
if (serverLevel.getEntity(uuid) instanceof LivingEntity livingEntity) {
this.trustedLastHurt = livingEntity;
this.trustedLastHurtBy = livingEntity.getLastHurtByMob();
int lastHurtByMobTimestamp = livingEntity.getLastHurtByMobTimestamp();
- return lastHurtByMobTimestamp != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.targetConditions);
+ return lastHurtByMobTimestamp != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.getTargetConditions()); // Leaf - Async target finding
}
}
@@ -1033,7 +1038,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
@Override
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
}
@Override
@@ -1097,6 +1102,13 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
Fox.this.setSitting(false);
super.start();
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.FoxEat;
+ }
+ // Leaf end - Async search block
}
class FoxFloatGoal extends FloatGoal {
diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java
index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d99a1f6baebdc7c4a700e3fee30d1b52f3c1ac3d 100644
--- a/net/minecraft/world/entity/animal/Panda.java
+++ b/net/minecraft/world/entity/animal/Panda.java
@@ -991,9 +991,18 @@ public class Panda extends Animal {
@Override
public boolean canUse() {
+ // Leaf start - Async look finding
+ if (poll()) {
+ return true;
+ }
if (this.mob.getRandom().nextFloat() >= this.probability) {
return false;
} else {
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ getLookAsync();
+ return false;
+ }
+ // Leaf end - Async look finding
if (this.lookAt == null) {
ServerLevel serverLevel = getServerLevel(this.mob);
if (this.lookAtType == Player.class) {
diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java
index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf19d89b673 100644
--- a/net/minecraft/world/entity/animal/Rabbit.java
+++ b/net/minecraft/world/entity/animal/Rabbit.java
@@ -642,7 +642,13 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
this.wantsToRaid = this.rabbit.wantsMoreFood();
}
- return super.canUse();
+ // Leaf start - Async search block
+ if (this.wantsToRaid && !this.canRaid) {
+ return super.canUse();
+ } else {
+ return false;
+ }
+ // Leaf end - Async search block
}
@Override
@@ -685,7 +691,7 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
@Override
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
blockState = level.getBlockState(pos.above());
if (blockState.getBlock() instanceof CarrotBlock && ((CarrotBlock)blockState.getBlock()).isMaxAge(blockState)) {
this.canRaid = true;
@@ -695,6 +701,13 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
return false;
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.RaidGarden;
+ }
+ // Leaf end - Async search block
}
public static enum Variant implements StringRepresentable {
diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java
index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..c5f626dcfe724f8ed19303d305f6eb5cfcc0f0af 100644
--- a/net/minecraft/world/entity/animal/Turtle.java
+++ b/net/minecraft/world/entity/animal/Turtle.java
@@ -527,8 +527,15 @@ public class Turtle extends Animal {
@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
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.TurtleToWater;
+ }
+ // Leaf end - Async search block
}
static class TurtleLayEggGoal extends MoveToBlockGoal {
@@ -584,8 +591,15 @@ public class Turtle extends Animal {
@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
+ }
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.TurtleLay;
}
+ // Leaf end - Async search block
}
static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables
diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java
index 7cb292de6b27fa4ba3c5fce526a4e939c576789f..68852158e2fd3c4ce241d722ac414d73ea3b8836 100644
--- a/net/minecraft/world/entity/animal/Wolf.java
+++ b/net/minecraft/world/entity/animal/Wolf.java
@@ -672,7 +672,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
@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
}
@Override
diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
index d44ed0d6a672a0b1eb0a8781e3e094096a2b753d..490c196419c94b75a540e64d513163df236eed0d 100644
--- a/net/minecraft/world/entity/monster/Drowned.java
+++ b/net/minecraft/world/entity/monster/Drowned.java
@@ -394,7 +394,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
@Override
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
}
@Override
@@ -408,6 +408,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
public void stop() {
super.stop();
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.Drowned;
+ }
+ // Leaf end - Async search block
}
static class DrownedGoToWaterGoal extends Goal {
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
index c7897532163d4fdf5a82982f7d24a47dd61e3dfa..2986384389c1acd311f4367d622550830ce009c1 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
@@ -597,10 +597,34 @@ public class EnderMan extends Monster implements NeutralMob {
@Override
public boolean canUse() {
+ // Leaf start - Async Target Finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (poll()) {
+ return true;
+ }
+ final EnderMan enderman = this.enderman;
+ final var ctx = enderman.getGoalCtx();
+ if (!ctx.state) return false;
+ final var level = getServerLevel(this.enderman);
+ final var cond = this.startAggroTargetConditions.range(this.getFollowDistance()).copy();
+ ctx.wake = () -> level.getNearestPlayer(cond, enderman);
+ return false;
+ }
+ // 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
+ protected boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof Player player)) return false;
+ var serverLevel = getServerLevel(this.enderman);
+ if (!this.startAggroTargetConditions.range(this.getFollowDistance()).test(serverLevel, enderman, player)) return false;
+ this.pendingTarget = player;
+ return true;
+ }
+ // Leaf end - Async Target Finding
+
@Override
public void start() {
this.aggroTime = this.adjustedTickDelay(5);
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
index ae4ee948971e931e4fdc4ec2187f5182195c626c..f4fa19c6352e44a624e81dc201b1d7d710c2d9d2 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
@@ -570,8 +570,15 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
@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
}
+
+ // Leaf start - Async search block
+ @Override
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.Strider;
+ }
+ // Leaf end - Async search block
}
static class StriderPathNavigation extends GroundPathNavigation {
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index ac7729d1caa80155697bfe0e8646e4eda5d1780e..2518ea7a9d2122ff55ab6546d21d7ed6cc933090 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1549,6 +1549,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
// Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks) - do not bother with condition work / make configurable
// Paper end - rewrite chunk system
+ ((ServerLevel) this).leafMidTickTasks(); // Leaf - Async target finding
}
}
this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals
@@ -1817,9 +1818,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@Override
public List<Entity> getEntities(@Nullable Entity entity, AABB boundingBox, Predicate<? super Entity> predicate) {
- 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<Entity> 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<Entity> list = Lists.newArrayList(); // Leaf - Async target finding - unused
+ // Leaf end - Async target finding
// Paper start - rewrite chunk system
final List<Entity> ret = new java.util.ArrayList<>();