mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
1956 lines
92 KiB
Diff
1956 lines
92 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 fee4a7452178c274eb835d758b718d8e874d79d0..9a2539e1fe2cee30066634ef47a991fa5837a5e4 100644
|
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
|
@@ -49,8 +49,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;
|
|
@@ -76,9 +78,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;
|
|
}
|
|
@@ -270,14 +278,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) {
|
|
@@ -304,14 +324,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 5ad00ebb9e0acab73a8366f0caf06979cfcccca0..9a68042d1efb0da915fc2a302641c9ea6d92f582 100644
|
|
--- a/net/minecraft/server/MinecraftServer.java
|
|
+++ b/net/minecraft/server/MinecraftServer.java
|
|
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public boolean lagging = false; // Purpur - Lagging threshold
|
|
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
|
|
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
|
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index 9b8d119116b0c3a51d3fe2ff7efb33cc39627cc4..436e73086678e4afbf94f1b7bca9b0c74266f762 100644
|
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -204,6 +204,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 a1c2e9018800339fca62d95c522da1bf254568fe..eb5e1e67db2ee1bdbedfa244088fcb7a9356bae3 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
|
|
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
|
|
@@ -220,6 +229,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
public boolean hasRidableMoveEvent = false; // Purpur - Ridables
|
|
final List<ServerPlayer> realPlayers; // Leaves - skip
|
|
public volatile @Nullable java.util.concurrent.Future<org.dreeam.leaf.async.tracker.TrackerCtx>[] trackerTask; // Leaf - Multithreaded tracker
|
|
+ public final @Nullable org.dreeam.leaf.async.ai.AsyncGoalExecutor asyncGoalExecutor; // Leaf - Async target finding
|
|
|
|
@Override
|
|
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
|
|
@@ -708,6 +718,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(this);
|
|
+ } else {
|
|
+ this.asyncGoalExecutor = null;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
|
|
// Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
|
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
|
index 6d9d8f85bf6936eee76c3d790dd676aa309a1d46..b19d2066b921d27f03b2c0af06fbf76fcb8d87b5 100644
|
|
--- a/net/minecraft/world/entity/LivingEntity.java
|
|
+++ b/net/minecraft/world/entity/LivingEntity.java
|
|
@@ -750,6 +750,12 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
|
|
super.remove(reason, eventCause); // CraftBukkit
|
|
this.brain.clearMemories();
|
|
+ // Leaf start - Async target finding
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled && this instanceof Mob mob) {
|
|
+ mob.targetSelector.ctx.cancel();
|
|
+ mob.goalSelector.ctx.cancel();
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
|
|
@Override
|
|
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
|
index 7caf9ea3792089dcf890c2af0ac17ee1d5c85c16..3882bc7a8d1684b91876eb7c6799949071e72626 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
|
|
private int homeRadius = -1;
|
|
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);
|
|
@@ -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) {
|
|
+ ((ServerLevel) this.level()).asyncGoalExecutor.tickMob(this);
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
// Paper end
|
|
|
|
@@ -792,6 +803,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) {
|
|
+ ((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..7b1f8e58f6b1fc34204b77cf3c902759aceb3350 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java
|
|
@@ -67,6 +67,13 @@ public class AvoidEntityGoal<T extends LivingEntity> extends Goal {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
+ // Leaf start - Async target 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),
|
|
@@ -76,6 +83,8 @@ public class AvoidEntityGoal<T extends LivingEntity> extends Goal {
|
|
this.mob.getY(),
|
|
this.mob.getZ()
|
|
);
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
if (this.toAvoid == null) {
|
|
return false;
|
|
} else {
|
|
@@ -91,6 +100,35 @@ public class AvoidEntityGoal<T extends LivingEntity> extends Goal {
|
|
}
|
|
}
|
|
|
|
+ // Leaf start - Async target 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.getY();
|
|
+ final double z = mob.getZ();
|
|
+ final var avoidClass = this.avoidClass;
|
|
+ final var bound = mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist);
|
|
+ ctx.wake = world -> world.getNearestEntity(
|
|
+ world.getEntitiesOfClass(avoidClass, bound, livingEntity -> true),
|
|
+ avoidEntityTargeting,
|
|
+ mob,
|
|
+ x,
|
|
+ y,
|
|
+ z
|
|
+ );
|
|
+ }
|
|
+ // 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..bc60bd9605a657f9f8de8c78100b8130a9f4b6ff 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/BegGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/BegGoal.java
|
|
@@ -27,8 +27,42 @@ 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 TargetingConditions begTargeting = this.begTargeting;
|
|
+ ctx.wake = world -> {
|
|
+ var player = world.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 +93,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..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 {
|
|
|
|
@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 target finding - diff on change
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.CatLie;
|
|
+ }
|
|
+ // 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..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 {
|
|
|
|
@Override
|
|
protected boolean isValidTarget(LevelReader level, BlockPos pos) {
|
|
- if (!level.isEmptyBlock(pos.above())) {
|
|
+ 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 target finding - 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 target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.CatSit;
|
|
+ }
|
|
+ // 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..dff33b2d10104ce5e9741141dc72e8bf5b8226cf 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java
|
|
@@ -23,8 +23,46 @@ 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);
|
|
+ ctx.wake = world -> {
|
|
+ List<AbstractBoat> entitiesOfClass = world.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;
|
|
|
|
@@ -36,7 +74,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..5396c98d0e691ecefd6cf482c2a1944c317ecec7 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 target finding
|
|
+ if (poll()) {
|
|
+ return true;
|
|
+ }
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
|
|
+ getFollowingMobAsync();
|
|
+ return false;
|
|
+ }
|
|
+ // Leaf end - Async target 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,35 @@ public class FollowMobGoal extends Goal {
|
|
return false;
|
|
}
|
|
|
|
+ // Leaf start - Async target 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 bound = this.mob.getBoundingBox().inflate(this.areaSize);
|
|
+ final var followPredicate = this.followPredicate;
|
|
+ ctx.wake = world -> {
|
|
+ List<Mob> entitiesOfClass = world.getEntitiesOfClass(Mob.class, bound, followPredicate);
|
|
+ if (!entitiesOfClass.isEmpty()) {
|
|
+ for (final Mob follow : entitiesOfClass) {
|
|
+ if (!follow.isInvisible()) {
|
|
+ return follow;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ };
|
|
+ }
|
|
+ // 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..ea5633edfd53b593b0772a43cca28a9e6f379439 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java
|
|
@@ -19,11 +19,55 @@ 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 pos = animal.position();
|
|
+ ctx.wake = world -> {
|
|
+ List<? extends Animal> entitiesOfClass = world.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 +87,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 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 {
|
|
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
|
|
}
|
|
|
|
public void removeAllGoals(Predicate<Goal> filter) {
|
|
this.availableGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal()));
|
|
+ availableGoalsDirty = true; // Leaf - Async target finding
|
|
}
|
|
|
|
// Paper start - EAR 2
|
|
@@ -61,18 +71,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)) {
|
|
@@ -83,7 +94,136 @@ public class GoalSelector {
|
|
return true;
|
|
}
|
|
|
|
+ // Leaf start - Async target finding
|
|
+ public final boolean poll() {
|
|
+ if (ctxState == -1 || this.ctxGoals == null || ctx.wake != null || ctxGoals.length == 0) {
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ 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 (this.ctxState == -1) {
|
|
+ if (this.availableGoalsDirty || this.ctxGoals == null) {
|
|
+ this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]);
|
|
+ this.availableGoalsDirty = false;
|
|
+ }
|
|
+ this.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();
|
|
@@ -114,6 +254,24 @@ 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;
|
|
+ } else {
|
|
+ for (WrappedGoal wrappedGoal : java.util.Objects.requireNonNull(this.ctxGoals)) {
|
|
+ if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) {
|
|
+ wrappedGoal.tick();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ 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..28e4c81ba8411147fe326bcf331d9ac1247d94c5 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
|
|
@@ -20,20 +20,82 @@ 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 pos = llama.position();
|
|
+ ctx.wake = world -> {
|
|
+ List<Entity> entities = world.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.searchEntity) {
|
|
+ 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 +107,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 +116,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..1b9729d3ecf7ab5b364cab26f940ac77da880014 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java
|
|
@@ -48,32 +48,78 @@ public class LookAtPlayerGoal extends Goal {
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
+ // Leaf start - Async target 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 bound = mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance);
|
|
+ final var lookAtContext = this.lookAtContext;
|
|
+ final var lookAtType = this.lookAtType;
|
|
+ ctx.wake = world -> {
|
|
+ if (lookAtType == Player.class) {
|
|
+ return world.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 world.getNearestEntity(
|
|
+ world
|
|
+ .getEntitiesOfClass(lookAtType, bound, livingEntity -> true),
|
|
+ lookAtContext,
|
|
+ mob,
|
|
+ x,
|
|
+ y,
|
|
+ z
|
|
);
|
|
}
|
|
-
|
|
- return this.lookAt != null;
|
|
- }
|
|
+ };
|
|
}
|
|
+ // 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..a6cb3b316c797cf85496ba395295c002805f573e 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
|
@@ -41,14 +41,73 @@ public abstract class MoveToBlockGoal extends Goal {
|
|
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP));
|
|
}
|
|
|
|
+ // 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.isValidTarget(this.mob.level(), blockPos1)) {
|
|
+ return false;
|
|
+ }
|
|
+ this.blockPos = blockPos1;
|
|
+ this.mob.movingTarget = blockPos1 == BlockPos.ZERO ? null : blockPos1;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ 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 false;
|
|
+ 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 homeRadius = mob.getHomeRadius();
|
|
+ final BlockPos homePos = mob.getHomePosition();
|
|
+ ctx.wake = world -> findNearestBlockAsync(ty, toRemove, mob, world, verticalSearchStart, searchRange, verticalSearchRange, blockPos, homeRadius, homePos);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ protected enum TypeToCheck {
|
|
+ CatLie,
|
|
+ CatSit,
|
|
+ Drowned,
|
|
+ FoxEat,
|
|
+ RaidGarden,
|
|
+ RemoveBlock,
|
|
+ Strider,
|
|
+ TurtleToWater,
|
|
+ TurtleLay,
|
|
+ Unknown,
|
|
+ }
|
|
+ // 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.nextStartTick > 0) {
|
|
this.nextStartTick--;
|
|
return false;
|
|
} else {
|
|
this.nextStartTick = this.nextStartTick(this.mob);
|
|
- return this.findNearestBlock();
|
|
+ return this.findNearestBlockAsync(); // Leaf - Async target finding
|
|
}
|
|
}
|
|
|
|
@@ -133,5 +192,108 @@ public abstract class MoveToBlockGoal extends Goal {
|
|
return false;
|
|
}
|
|
|
|
+ // 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,
|
|
+ final PathfinderMob mob,
|
|
+ final net.minecraft.server.level.ServerLevel serverLevel,
|
|
+ final int verticalSearchStart,
|
|
+ final int searchRange,
|
|
+ final int verticalSearchRange,
|
|
+ final BlockPos blockPos,
|
|
+ final float homeRadius,
|
|
+ final BlockPos homePos
|
|
+ ) {
|
|
+ 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 (isWithinHome(homeRadius, homePos, mutableBlockPos)
|
|
+ && isValidTargetAsync(ty, toRemove, mob, serverLevel, mutableBlockPos)) {
|
|
+ return mutableBlockPos.immutable();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ private static boolean isWithinHome(float homeRadius, BlockPos homePos, BlockPos pos) {
|
|
+ return homeRadius == -1.0F || homePos.distSqr(pos) < homeRadius * homeRadius;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
+
|
|
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.Unknown;
|
|
+ }
|
|
+
|
|
+ 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 Unknown -> throw new IllegalStateException();
|
|
+ case null -> throw new IllegalStateException();
|
|
+ }
|
|
+ // 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..569b344c190d60c10d33dad90cf1ae19a917d997 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 target finding
|
|
if (!this.golem.level().isBrightOutside()) {
|
|
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 target finding
|
|
} else {
|
|
this.villager = getServerLevel(this.golem)
|
|
.getNearestEntity(
|
|
@@ -38,6 +48,35 @@ public class OfferFlowerGoal extends Goal {
|
|
}
|
|
}
|
|
|
|
+
|
|
+ // Leaf start - Async target 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 bound = golem.getBoundingBox().inflate(6.0, 2.0, 6.0);
|
|
+ ctx.wake = world -> world.getNearestEntity(
|
|
+ world.getEntitiesOfClass(Villager.class, bound, livingEntity -> true),
|
|
+ OFFER_TARGER_CONTEXT,
|
|
+ golem,
|
|
+ x,
|
|
+ y,
|
|
+ z
|
|
+ );
|
|
+ }
|
|
+ // 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..e3bb4c5850e25405a243aaf57e2e8b1c64381d1d 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
|
|
@@ -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 target finding
|
|
+ if (poll()) {
|
|
+ this.nextStartTick = reducedTickDelay(20);
|
|
+ return true;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
+ if (this.nextStartTick > 0) {
|
|
this.nextStartTick--;
|
|
return false;
|
|
- } 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 target finding - diff on change
|
|
&& chunk.getBlockState(pos.above()).isAir()
|
|
&& chunk.getBlockState(pos.above(2)).isAir();
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.RemoveBlock;
|
|
+ }
|
|
+ // 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..7d3d5c73d31370c89cd4953e7245ca644bcf92e3 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
|
|
@@ -49,14 +49,42 @@ public class TemptGoal extends Goal {
|
|
this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity));
|
|
}
|
|
|
|
+ // Leaf start - Async target 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 conditions = this.targetingConditions
|
|
+ .range(mob.getAttributeValue(Attributes.TEMPT_RANGE))
|
|
+ .copy();
|
|
+ ctx.wake = world -> world.getNearestPlayer(conditions, mob);
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
@Override
|
|
public boolean canUse() {
|
|
if (this.calmDown > 0) {
|
|
this.calmDown--;
|
|
return false;
|
|
} else {
|
|
- this.player = getServerLevel(this.mob)
|
|
- .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
|
|
+ // Leaf start - Async target finding
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
|
|
+ if (!poll()) {
|
|
+ getNearestPlayerAsync();
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ this.player = getServerLevel(this.mob)
|
|
+ .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
// 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..66f2d0121bc90ada6c2aeac31a10d57682466e4b 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
|
|
@@ -24,13 +24,51 @@ 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;
|
|
+ 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);
|
|
+ ctx.wake = world -> {
|
|
+ List<Villager> nearbyEntities = world.getNearbyEntities(Villager.class, attackTargeting, mob, bound);
|
|
+ List<Player> nearbyPlayers = world.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 (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
|
|
+ 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);
|
|
List<Player> nearbyPlayers = serverLevel.getNearbyPlayers(this.attackTargeting, this.golem, aabb);
|
|
|
|
+ // Async target finding - diff
|
|
for (LivingEntity livingEntity : nearbyEntities) {
|
|
Villager villager = (Villager)livingEntity;
|
|
|
|
@@ -41,6 +79,8 @@ public class DefendVillageTargetGoal extends TargetGoal {
|
|
}
|
|
}
|
|
}
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
|
|
return this.potentialTarget != null && !(this.potentialTarget instanceof Player player1 && (player1.isSpectator() || player1.isCreative()));
|
|
}
|
|
diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
|
|
index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..65156222eb93c5a59163c407f62d0a1f848043d0 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
|
|
@@ -73,6 +73,45 @@ 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 target finding
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) {
|
|
+ final var self = this.mob;
|
|
+ final var ctx = self.getGoalCtx();
|
|
+ if (!ctx.state) return;
|
|
+ final Class<?>[] toIgnoreAlert = this.toIgnoreAlert;
|
|
+ ctx.wake = world -> {
|
|
+ var toAlert = new java.util.ArrayList<Mob>();
|
|
+ List<? extends Mob> entitiesOfClass = world
|
|
+ .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 target finding
|
|
+
|
|
List<? extends Mob> entitiesOfClass = this.mob
|
|
.level()
|
|
.getEntitiesOfClass((Class<? extends Mob>)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS);
|
|
@@ -87,7 +126,7 @@ public class HurtByTargetGoal extends TargetGoal {
|
|
|
|
mob = (Mob)var5.next();
|
|
if (this.mob != mob
|
|
- && mob.getTarget() == null
|
|
+ && 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) {
|
|
@@ -96,7 +135,7 @@ public class HurtByTargetGoal extends TargetGoal {
|
|
|
|
boolean flag = false;
|
|
|
|
- for (Class<?> clazz : this.toIgnoreAlert) {
|
|
+ for (Class<?> clazz : this.toIgnoreAlert) { // Leaf - Async target finding - diff on change
|
|
if (mob.getClass() == clazz) {
|
|
flag = true;
|
|
break;
|
|
@@ -113,6 +152,36 @@ public class HurtByTargetGoal extends TargetGoal {
|
|
}
|
|
}
|
|
|
|
+ // Leaf start - Async target finding
|
|
+ public void poll() {
|
|
+ if (!(this.mob.getGoalCtx().result() instanceof List<?> toAlert)) return;
|
|
+ LivingEntity lastHurtByMob = this.mob.getLastHurtByMob();
|
|
+ if (lastHurtByMob == null || (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 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..048c4965f94790daa58088c26d7fd9c7172985a4 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
|
@@ -41,12 +41,51 @@ 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;
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ 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());
|
|
+ ctx.wake = world -> {
|
|
+ if (targetType != Player.class && targetType != ServerPlayer.class) {
|
|
+ return world.getNearestEntity(world.getEntitiesOfClass(targetType, targetSearch, entity -> entity != null && entity != mob && entity.isAlive()), targetConditions, mob, x, y, z);
|
|
+ } else {
|
|
+ return world.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 {
|
|
- this.findTarget();
|
|
+ this.findTargetAsync(); // Async target finding
|
|
return this.target != null;
|
|
}
|
|
}
|
|
@@ -57,6 +96,7 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
|
|
|
protected void findTarget() {
|
|
ServerLevel serverLevel = getServerLevel(this.mob);
|
|
+
|
|
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..84c7b89e7c894c0f544cf0ffcf9dff3f6a5919cc 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
|
|
@@ -23,12 +23,20 @@ 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;
|
|
} 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
|
|
+++ 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..6754f43767bde0bb6432a33aedd5b8e8d568ae40 100644
|
|
--- a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java
|
|
+++ b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java
|
|
@@ -37,6 +37,26 @@ public class ResetUniversalAngerTargetGoal<T extends Mob & NeutralMob> extends G
|
|
this.lastHurtByPlayerTimestamp = this.mob.getLastHurtByMobTimestamp();
|
|
this.mob.forgetCurrentTargetAndRefreshUniversalAnger();
|
|
if (this.alertOthersOfSameType) {
|
|
+ // Leaf start - Async target finding
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) {
|
|
+ final var mob = this.mob;
|
|
+ final var ctx = mob.getGoalCtx();
|
|
+ if (!ctx.state) return;
|
|
+ final double followRange = this.mob.getAttributeValue(Attributes.FOLLOW_RANGE);
|
|
+ final AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followRange, 10.0, followRange);
|
|
+ ctx.wake = world -> {
|
|
+ List<? extends Mob> entities = world.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 target finding
|
|
this.getNearbyMobsOfSameType()
|
|
.stream()
|
|
.filter(mob -> mob != this.mob)
|
|
@@ -47,7 +67,19 @@ public class ResetUniversalAngerTargetGoal<T extends Mob & NeutralMob> extends G
|
|
super.start();
|
|
}
|
|
|
|
+ // Leaf start - Async target finding
|
|
+ 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 target finding
|
|
+
|
|
private List<? extends Mob> getNearbyMobsOfSameType() {
|
|
+ // 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);
|
|
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 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 {
|
|
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 (EntityReference<LivingEntity> entityReference : Fox.this.getTrustedEntities().toList()) {
|
|
LivingEntity livingEntity = entityReference.getEntity(serverLevel, LivingEntity.class);
|
|
@@ -874,7 +879,7 @@ public class Fox extends Animal {
|
|
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
|
|
}
|
|
}
|
|
|
|
@@ -1053,7 +1058,7 @@ public class Fox extends Animal {
|
|
@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 target finding - diff on change
|
|
}
|
|
|
|
@Override
|
|
@@ -1117,6 +1122,13 @@ public class Fox extends Animal {
|
|
Fox.this.setSitting(false);
|
|
super.start();
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.FoxEat;
|
|
+ }
|
|
+ // 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..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 target 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 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 041ccb96d36cbe0f5683ff6e8b2adb0b79a96738..aae1e9691725e40864764c0ad3862a35cce0a6d9 100644
|
|
--- a/net/minecraft/world/entity/animal/Rabbit.java
|
|
+++ b/net/minecraft/world/entity/animal/Rabbit.java
|
|
@@ -678,7 +678,13 @@ public class Rabbit extends Animal {
|
|
this.wantsToRaid = this.rabbit.wantsMoreFood();
|
|
}
|
|
|
|
- return super.canUse();
|
|
+ // Leaf start - Async target finding
|
|
+ if (this.wantsToRaid && !this.canRaid) {
|
|
+ return super.canUse();
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
|
|
@Override
|
|
@@ -721,7 +727,7 @@ public class Rabbit extends Animal {
|
|
@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 target finding - diff on change
|
|
blockState = level.getBlockState(pos.above());
|
|
if (blockState.getBlock() instanceof CarrotBlock && ((CarrotBlock)blockState.getBlock()).isMaxAge(blockState)) {
|
|
this.canRaid = true;
|
|
@@ -731,6 +737,13 @@ public class Rabbit extends Animal {
|
|
|
|
return false;
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.RaidGarden;
|
|
+ }
|
|
+ // 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..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 {
|
|
|
|
@Override
|
|
protected boolean isValidTarget(LevelReader level, BlockPos pos) {
|
|
- return level.getBlockState(pos).is(Blocks.WATER);
|
|
+ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async target finding - diff on change
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.TurtleToWater;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
|
|
static class TurtleLayEggGoal extends MoveToBlockGoal {
|
|
@@ -538,8 +545,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 target finding - diff on change
|
|
+ }
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.TurtleLay;
|
|
}
|
|
+ // 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..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 {
|
|
|
|
@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 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 {
|
|
@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 target finding - diff on change
|
|
}
|
|
|
|
@Override
|
|
@@ -405,6 +405,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
|
public void stop() {
|
|
super.stop();
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.Drowned;
|
|
+ }
|
|
+ // Leaf end - Async target finding
|
|
}
|
|
|
|
static class DrownedGoToWaterGoal extends Goal {
|
|
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
|
|
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 {
|
|
|
|
@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 target finding - diff on change
|
|
}
|
|
+
|
|
+ // Leaf start - Async target finding
|
|
+ @Override
|
|
+ protected TypeToCheck typeToCheck() {
|
|
+ return TypeToCheck.Strider;
|
|
+ }
|
|
+ // 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 523b068b99236845e2b87361f72494582e6dd894..9b4e6fdbedfa378ea436cdd5f1a36e2b3d94be17 100644
|
|
--- a/net/minecraft/world/level/Level.java
|
|
+++ b/net/minecraft/world/level/Level.java
|
|
@@ -1793,9 +1793,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
|
|
@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<>();
|