mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-23 17:09:29 +00:00
update async target finding and block finding (#296)
* reduce overhead on poll * more async search entities * async block search * rename search entity config * cleanup * fix async search block too frequent * remove alertOther Experimental anno * Adjust the delay of RemoveBlockGoal to match vanilla behavior * Optimize TemptGoal * rollback interval change * cleanup * add async finding to DefendVillageTargetGoal * rollback interval change for NearestHealableRaiderTargetGoal * config searchPlayer * fix DefendVillageTargetGoal condition doesn't check * add async finding to BegGoal * rollback interval change for FollowMobGoal * cleanup * add async finding to some follow goal * add async finding to TemptGoal * handle searchPlayer config * fix TemptGoal
This commit is contained in:
@@ -1,183 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 23 Mar 2025 11:51:44 +0100
|
||||
Subject: [PATCH] Async Block Finding
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..d70ed3ace6fa8f97bcc0d493842f44f43072a610 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
@@ -20,6 +20,18 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
private final int verticalSearchRange;
|
||||
protected int verticalSearchStart;
|
||||
|
||||
+ // Leaf start - Async Block Finding
|
||||
+ private static final java.util.concurrent.ExecutorService BLOCK_FINDER_EXECUTOR =
|
||||
+ java.util.concurrent.Executors.newSingleThreadExecutor(
|
||||
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
+ .setNameFormat("Leaf Block Finding Thread - %d")
|
||||
+ .setDaemon(true)
|
||||
+ .build());
|
||||
+
|
||||
+ private final java.util.concurrent.ConcurrentLinkedQueue<BlockPos> candidateBlocks = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||
+ private boolean asyncSearchInProgress = false;
|
||||
+ // Leaf end - Async Block Finding
|
||||
+
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange) {
|
||||
this(mob, speedModifier, searchRange, 1);
|
||||
}
|
||||
@@ -29,6 +41,10 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
super.stop();
|
||||
this.blockPos = BlockPos.ZERO;
|
||||
this.mob.movingTarget = null;
|
||||
+ // Leaf start - Async Block Finding - Reset async state on goal stop
|
||||
+ this.candidateBlocks.clear();
|
||||
+ this.asyncSearchInProgress = false;
|
||||
+ // Leaf end - Async Block Finding - Reset async state on goal stop
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -53,23 +69,23 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
}
|
||||
|
||||
protected int nextStartTick(PathfinderMob creature) {
|
||||
- return reducedTickDelay(200 + creature.getRandom().nextInt(200));
|
||||
+ return Goal.reducedTickDelay(200 + creature.getRandom().nextInt(200)); // Leaf - Async Block Finding - Use the static method from the Goal class directly
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinueToUse() {
|
||||
- return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.isValidTarget(this.mob.level(), this.blockPos);
|
||||
+ return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.blockPos != BlockPos.ZERO && this.isValidTarget(this.mob.level(), this.blockPos); // Leaf - Async Block Finding
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
- this.moveMobToBlock();
|
||||
+ if (this.blockPos != BlockPos.ZERO) this.moveMobToBlock(); // Leaf - Async Block Finding
|
||||
this.tryTicks = 0;
|
||||
this.maxStayTicks = this.mob.getRandom().nextInt(this.mob.getRandom().nextInt(1200) + 1200) + 1200;
|
||||
}
|
||||
|
||||
protected void moveMobToBlock() {
|
||||
- this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier);
|
||||
+ if (this.blockPos != BlockPos.ZERO) this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier); // Leaf - Async Block Finding
|
||||
}
|
||||
|
||||
public double acceptedDistance() {
|
||||
@@ -77,7 +93,7 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
}
|
||||
|
||||
protected BlockPos getMoveToTarget() {
|
||||
- return this.blockPos.above();
|
||||
+ return this.blockPos != BlockPos.ZERO ? this.blockPos.above() : BlockPos.ZERO; // Leaf - Async Block Finding
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,7 +103,10 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ if (this.blockPos == BlockPos.ZERO) return; // Leaf - Async Block Finding
|
||||
BlockPos moveToTarget = this.getMoveToTarget();
|
||||
+ if (moveToTarget == BlockPos.ZERO) return; // Leaf - Async Block Finding
|
||||
+
|
||||
if (!moveToTarget.closerToCenterThan(this.mob.position(), this.acceptedDistance())) {
|
||||
this.reachedTarget = false;
|
||||
this.tryTicks++;
|
||||
@@ -109,20 +128,90 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
}
|
||||
|
||||
protected boolean findNearestBlock() {
|
||||
+ // Leaf start - Async Block Finding
|
||||
+ if (!org.dreeam.leaf.config.modules.async.AsyncBlockFinding.enabled) {
|
||||
+ return findNearestBlockSync();
|
||||
+ }
|
||||
+
|
||||
+ while (!candidateBlocks.isEmpty()) {
|
||||
+ BlockPos pos = candidateBlocks.poll();
|
||||
+ if (pos != null && this.mob.level().hasChunkAt(pos) &&
|
||||
+ this.mob.isWithinRestriction(pos) &&
|
||||
+ this.isValidTarget(this.mob.level(), pos)) {
|
||||
+
|
||||
+ this.blockPos = pos;
|
||||
+ this.mob.movingTarget = this.blockPos == BlockPos.ZERO ? null : this.blockPos; // Use the assigned blockPos
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (asyncSearchInProgress) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // Check again before starting, avoids tiny race condition if canUse is called rapidly
|
||||
+ if (!asyncSearchInProgress) {
|
||||
+ asyncSearchInProgress = true;
|
||||
+ final BlockPos centerPos = this.mob.blockPosition().immutable();
|
||||
+ final int searchRange = this.searchRange;
|
||||
+ final int verticalRange = this.verticalSearchRange;
|
||||
+ final int verticalStart = this.verticalSearchStart;
|
||||
+
|
||||
+ BLOCK_FINDER_EXECUTOR.execute(() -> {
|
||||
+ try {
|
||||
+ generateCandidateBlocks(centerPos, searchRange, verticalRange, verticalStart);
|
||||
+ } catch (Exception e) {
|
||||
+ e.printStackTrace(); // Keep basic error logging
|
||||
+ } finally {
|
||||
+ asyncSearchInProgress = false;
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private void generateCandidateBlocks(BlockPos center, int searchRange, int verticalRange, int verticalStart) {
|
||||
+ java.util.List<BlockPos> positions = new java.util.ArrayList<>();
|
||||
+
|
||||
+ for (int i2 = verticalStart; i2 <= verticalRange; 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) {
|
||||
+ BlockPos pos = center.offset(i4, i2 - 1, i5);
|
||||
+ positions.add(pos.immutable());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ positions.sort((p1, p2) -> {
|
||||
+ double d1 = p1.distSqr(center);
|
||||
+ double d2 = p2.distSqr(center);
|
||||
+ return Double.compare(d1, d2);
|
||||
+ });
|
||||
+
|
||||
+ for (BlockPos pos : positions) {
|
||||
+ candidateBlocks.add(pos);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected boolean findNearestBlockSync() {
|
||||
+ // Leaf end - Async Block Finding
|
||||
int i = this.searchRange;
|
||||
int i1 = this.verticalSearchRange;
|
||||
- BlockPos blockPos = this.mob.blockPosition();
|
||||
+ BlockPos blockPosOrigin = this.mob.blockPosition(); // Leaf - Async Block Finding
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (int i2 = this.verticalSearchStart; i2 <= i1; i2 = i2 > 0 ? -i2 : 1 - i2) {
|
||||
for (int i3 = 0; i3 < i; 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);
|
||||
+ mutableBlockPos.setWithOffset(blockPosOrigin, i4, i2 - 1, i5); // Leaf - Async Block Finding
|
||||
if (!this.mob.level().hasChunkAt(mutableBlockPos)) continue; // Gale - Airplane - block goal does not load chunks - if this block isn't loaded, continue
|
||||
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) {
|
||||
- this.blockPos = mutableBlockPos;
|
||||
- this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper
|
||||
+ this.blockPos = mutableBlockPos.immutable(); // Leaf - Async Block Finding
|
||||
+ this.mob.movingTarget = this.blockPos == BlockPos.ZERO ? null : this.blockPos; // Paper // Leaf - Async Block Finding - Use the assigned blockPos
|
||||
return true;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,614 +0,0 @@
|
||||
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/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 24926aa7ed5c78b235659daf18b224b14beb744c..53716dcdb9d3409b7bc71f3064be42bc3f81a86b 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1088,6 +1088,12 @@ 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
|
||||
+ org.dreeam.leaf.async.ai.AsyncGoalExecutor.EXECUTOR.shutdown();
|
||||
+ try {
|
||||
+ org.dreeam.leaf.async.ai.AsyncGoalExecutor.EXECUTOR.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
|
||||
+ } catch (java.lang.InterruptedException ignored) {}
|
||||
+ // Leaf end - Async target finding
|
||||
}
|
||||
|
||||
public String getLocalIp() {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 90bdcd168ad5b1a940f81b191bd59a34d3a33070..a0eb0dc2d17928108a334710e14a0d4b9eea06c8 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 List<Runnable> asyncAITasks = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Leaf
|
||||
|
||||
public LevelChunk getChunkIfLoaded(int x, int z) {
|
||||
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
|
||||
@@ -861,6 +871,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
);
|
||||
this.tickBlockEntities();
|
||||
+ // Leaf start - Async target finding
|
||||
+ final List<Runnable> tasks = this.asyncAITasks;
|
||||
+ this.asyncAITasks = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ org.dreeam.leaf.async.ai.AsyncGoalExecutor.EXECUTOR.execute(() -> {
|
||||
+ for (Runnable asyncTask : tasks) {
|
||||
+ asyncTask.run();
|
||||
+ }
|
||||
+ });
|
||||
+ // Leaf end - Async target finding
|
||||
}
|
||||
|
||||
// Paper - rewrite chunk system
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 075fcbcde23b5bb7b27ff622e8d188c3a2583973..e5aa7c542b1e9c9362aa1feeeebef45919feac70 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -243,6 +243,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
protected Vec3 stuckSpeedMultiplier = Vec3.ZERO;
|
||||
@Nullable
|
||||
private Entity.RemovalReason removalReason;
|
||||
+ private final java.util.concurrent.atomic.AtomicBoolean isRemoved = new java.util.concurrent.atomic.AtomicBoolean(false); // Leaf - atomic removal check
|
||||
public static final float DEFAULT_BB_WIDTH = 0.6F;
|
||||
public static final float DEFAULT_BB_HEIGHT = 1.8F;
|
||||
public float moveDist;
|
||||
@@ -5028,7 +5029,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public final boolean isRemoved() {
|
||||
- return this.removalReason != null;
|
||||
+ // Leaf start - atomic removal check
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ return this.isRemoved.getAcquire();
|
||||
+ } else {
|
||||
+ return this.removalReason != null;
|
||||
+ }
|
||||
+ // Leaf end - atomic removal check
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -5055,6 +5062,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
|
||||
if (this.removalReason == null) {
|
||||
this.removalReason = removalReason;
|
||||
+ // Leaf start - atomic removal check
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ this.isRemoved.setRelease(true);
|
||||
+ }
|
||||
+ // Leaf end - atomic removal check
|
||||
}
|
||||
|
||||
if (this.removalReason.shouldDestroy()) {
|
||||
@@ -5074,6 +5086,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
public void unsetRemoved() {
|
||||
this.removalReason = null;
|
||||
+ // Leaf start - atomic removal check
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ this.isRemoved.setRelease(false);
|
||||
+ }
|
||||
+ // Leaf end - atomic removal check
|
||||
}
|
||||
|
||||
// Paper start - Folia schedulers
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index e82e32407cec6109b9c3b0106295217f4a3f4aa2..d7361d2f0a777f745133c3687637ba6ab451af5b 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -22,17 +22,30 @@ public class GoalSelector {
|
||||
};
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
|
||||
+ private final java.util.List<WrappedGoal> asyncGoals = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Leaf
|
||||
private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from 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
|
||||
|
||||
public void addGoal(int priority, Goal goal) {
|
||||
- this.availableGoals.add(new WrappedGoal(priority, goal));
|
||||
+ // Leaf start
|
||||
+ WrappedGoal wrapped = new WrappedGoal(priority, goal);
|
||||
+ if (this.availableGoals.add(wrapped)
|
||||
+ && org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled
|
||||
+ && goal instanceof org.dreeam.leaf.async.ai.AsyncGoal) {
|
||||
+ asyncGoals.add(wrapped);
|
||||
+ }
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void removeAllGoals(Predicate<Goal> filter) {
|
||||
this.availableGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal()));
|
||||
+ // Leaf start
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ this.asyncGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal()));
|
||||
+ }
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
// Paper start - EAR 2
|
||||
@@ -41,8 +54,37 @@ public class GoalSelector {
|
||||
tickRate = Math.min(tickRate, 3); // Dreeam TODO - Waiting Paper
|
||||
this.curRate++;
|
||||
//return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct
|
||||
- return this.curRate % tickRate == 0;
|
||||
+ // Leaf start
|
||||
+ boolean willTick = this.curRate % tickRate == 0;
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ for (var wrappedGoal : this.asyncGoals) {
|
||||
+ if (wrappedGoal.getGoal() instanceof org.dreeam.leaf.async.ai.AsyncGoal asyncGoal
|
||||
+ && asyncGoal.poll()
|
||||
+ && !willTick) {
|
||||
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) {
|
||||
+ wrappedGoal.stop();
|
||||
+ }
|
||||
+ if (!wrappedGoal.isRunning() && !goalContainsAnyFlags(wrappedGoal, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoal, this.lockedFlags) && wrappedGoal.canUse()) {
|
||||
+ long flagIterator = wrappedGoal.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = wrappedGoal.getFlags().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);
|
||||
+ // Paper end
|
||||
+ WrappedGoal wrappedGoal1 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
||||
+ wrappedGoal1.stop();
|
||||
+ this.lockedFlags.put(flag, wrappedGoal);
|
||||
+ }
|
||||
+
|
||||
+ wrappedGoal.start();
|
||||
+ // wrappedGoal.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return willTick;
|
||||
// Pufferfish end
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
public boolean hasTasks() {
|
||||
@@ -63,6 +105,11 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
this.availableGoals.removeIf(wrappedGoal1 -> wrappedGoal1.getGoal() == goal);
|
||||
+ // Leaf start
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ this.asyncGoals.removeIf(wrappedGoal1 -> wrappedGoal1.getGoal() == goal);
|
||||
+ }
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
// Paper start - Perf: optimize goal types
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
index 41ee3cdc45ecc8376a2203ed588bb544ed377294..49e836a012f0db9dec6578caa341a50e703ee98e 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
@@ -11,13 +11,20 @@ import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
-public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetGoal {
|
||||
+public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetGoal implements org.dreeam.leaf.async.ai.AsyncGoal { // Leaf
|
||||
private static final int DEFAULT_RANDOM_INTERVAL = 10;
|
||||
protected final Class<T> targetType;
|
||||
protected final int randomInterval;
|
||||
@Nullable
|
||||
protected LivingEntity target;
|
||||
- protected TargetingConditions targetConditions;
|
||||
+ @Nullable protected TargetingConditions.Selector selector; // Leaf - create TargetingConditions instead of reusing it
|
||||
+ // Leaf start - Async Target Finding
|
||||
+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("Leaf Async Target Lookup");
|
||||
+ // Flag to track if a search is in progress
|
||||
+ private final java.util.concurrent.atomic.AtomicBoolean isSearching = new java.util.concurrent.atomic.AtomicBoolean(false);
|
||||
+ private final java.util.concurrent.atomic.AtomicReference<LivingEntity> pendingTarget = new java.util.concurrent.atomic.AtomicReference<>(null);
|
||||
+ protected boolean readyNow = false;
|
||||
+ // Leaf end - Async Target Finding
|
||||
|
||||
public NearestAttackableTargetGoal(Mob mob, Class<T> targetType, boolean mustSee) {
|
||||
this(mob, targetType, 10, mustSee, false, null);
|
||||
@@ -38,11 +45,17 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
this.targetType = targetType;
|
||||
this.randomInterval = reducedTickDelay(interval);
|
||||
this.setFlags(EnumSet.of(Goal.Flag.TARGET));
|
||||
- this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector);
|
||||
+ this.selector = selector; // Leaf
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
+ // Leaf start - Async target finding
|
||||
+ if (readyNow) {
|
||||
+ readyNow = false;
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Leaf end - Async target finding
|
||||
if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -55,8 +68,37 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
return this.mob.getBoundingBox().inflate(targetDistance, targetDistance, targetDistance);
|
||||
}
|
||||
|
||||
+ // Leaf start - Async target finding
|
||||
+ @Override
|
||||
+ public boolean poll() {
|
||||
+ LivingEntity t = pendingTarget.getAndSet(null);
|
||||
+ if (t == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ ServerLevel serverLevel = getServerLevel(this.mob);
|
||||
+ if (serverLevel == null || !t.isAlive() || !this.getTargetConditions().test(serverLevel, this.mob, t)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ this.target = t;
|
||||
+ if (this.readyNow) {
|
||||
+ LOGGER.warn("NearestAttackableTargetGoal#findTarget call twice");
|
||||
+ }
|
||||
+ this.readyNow = true;
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
protected void findTarget() {
|
||||
ServerLevel serverLevel = getServerLevel(this.mob);
|
||||
+
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ this.findTargetAsync();
|
||||
+ if (serverLevel == null || this.target == null || !this.target.isAlive() || !this.getTargetConditions().test(serverLevel, this.mob, this.target)) {
|
||||
+ this.target = null;
|
||||
+ return;
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
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),
|
||||
@@ -71,6 +113,156 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
}
|
||||
}
|
||||
|
||||
+ private void findTargetAsync() {
|
||||
+ if (!isSearching.compareAndSet(false, true)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Capture mutable state to avoid race conditions
|
||||
+ final Mob mob = this.mob;
|
||||
+
|
||||
+ // Safety check
|
||||
+ if (mob == null || mob.isRemoved() || !mob.isAlive()) {
|
||||
+ isSearching.setRelease(false);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final double x = mob.getX();
|
||||
+ final double y = mob.getEyeY();
|
||||
+ final double z = mob.getZ();
|
||||
+ final double followDistance = this.getFollowDistance();
|
||||
+ final TargetingConditions targetConditions = this.getTargetConditions();
|
||||
+ final Class<T> targetType = this.targetType;
|
||||
+ final double maxDistSqr = followDistance * followDistance;
|
||||
+ final AABB targetSearch = getTargetSearchArea(this.getFollowDistance());
|
||||
+ final ServerLevel serverLevel = getServerLevel(mob);
|
||||
+
|
||||
+ serverLevel.asyncAITasks.add(() -> {
|
||||
+ try {
|
||||
+ if (mob.level() == null || mob.level() != serverLevel) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (mob.isRemoved() || !mob.isAlive()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (targetType != Player.class && targetType != ServerPlayer.class) {
|
||||
+ java.util.List<T> entities;
|
||||
+ try {
|
||||
+ entities = mob.level().getEntitiesOfClass(targetType, targetSearch, entity -> entity != null && entity != mob && !entity.isRemoved() && entity.isAlive());
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.warn("Exception getting entities", e);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (entities != null && !entities.isEmpty()) {
|
||||
+ var result = findNearestEntitySafely(entities, targetConditions, mob, x, y, z, serverLevel, maxDistSqr);
|
||||
+ pendingTarget.setRelease(result);
|
||||
+ }
|
||||
+ } else {
|
||||
+ var result = findNearestPlayerSafely(targetConditions, mob, x, y, z, serverLevel);
|
||||
+ pendingTarget.setRelease(result);
|
||||
+ }
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.warn("Exception during async target finding", e);
|
||||
+ } finally {
|
||||
+ isSearching.setRelease(false);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static LivingEntity findNearestEntitySafely(
|
||||
+ java.util.List<? extends LivingEntity> entities,
|
||||
+ TargetingConditions conditions,
|
||||
+ Mob source,
|
||||
+ double x,
|
||||
+ double y,
|
||||
+ double z,
|
||||
+ ServerLevel level,
|
||||
+ double maxDistSqr) {
|
||||
+
|
||||
+ if (entities == null || entities.isEmpty() || level == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ double closestDistSq = maxDistSqr;
|
||||
+ LivingEntity closest = null;
|
||||
+
|
||||
+ for (LivingEntity entity : entities) {
|
||||
+ if (entity == null || entity == source || entity.isRemoved() || !entity.isAlive()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (conditions.test(level, source, entity)) {
|
||||
+ double dx = entity.getX() - x;
|
||||
+ double dy = entity.getY() - y;
|
||||
+ double dz = entity.getZ() - z;
|
||||
+ double distSq = dx * dx + dy * dy + dz * dz;
|
||||
+
|
||||
+ if (distSq < closestDistSq) {
|
||||
+ closestDistSq = distSq;
|
||||
+ closest = entity;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return closest;
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.error("Exception in findNearestEntitySafely", e);
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static Player findNearestPlayerSafely(
|
||||
+ TargetingConditions conditions,
|
||||
+ Mob source,
|
||||
+ double x,
|
||||
+ double y,
|
||||
+ double z,
|
||||
+ ServerLevel level) {
|
||||
+
|
||||
+ if (level == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ java.util.List<? extends Player> players = level.players();
|
||||
+ if (players == null || players.isEmpty()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ double closestDistSq = -1.0;
|
||||
+ Player closest = null;
|
||||
+
|
||||
+ for (Player player : players) {
|
||||
+ if (player == null || player.isRemoved() || !player.isAlive()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (conditions.test(level, source, player)) {
|
||||
+ double dx = player.getX() - x;
|
||||
+ double dy = player.getY() - y;
|
||||
+ double dz = player.getZ() - z;
|
||||
+ double distSq = dx * dx + dy * dy + dz * dz;
|
||||
+
|
||||
+ if (closestDistSq == -1.0 || distSq < closestDistSq) {
|
||||
+ closestDistSq = distSq;
|
||||
+ closest = player;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return closest;
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.error("Exception in findNearestPlayerSafely", e);
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Async target finding
|
||||
+
|
||||
@Override
|
||||
public void start() {
|
||||
this.mob.setTarget(this.target, this.target instanceof ServerPlayer ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit - reason
|
||||
@@ -81,7 +273,9 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
- private TargetingConditions getTargetConditions() {
|
||||
- return this.targetConditions.range(this.getFollowDistance());
|
||||
+ // Leaf start
|
||||
+ protected TargetingConditions getTargetConditions() {
|
||||
+ return TargetingConditions.forCombat().range(this.getFollowDistance()).selector(this.selector);
|
||||
}
|
||||
+ // Leaf end
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
|
||||
index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..af9101bb0639dedee41e2e3e97e05cad91ec42e7 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
|
||||
@@ -10,7 +10,7 @@ public class NearestHealableRaiderTargetGoal<T extends LivingEntity> extends Nea
|
||||
private int cooldown = 0;
|
||||
|
||||
public NearestHealableRaiderTargetGoal(Raider raider, Class<T> targetType, boolean mustSee, @Nullable TargetingConditions.Selector selector) {
|
||||
- super(raider, targetType, 500, mustSee, false, selector);
|
||||
+ super(raider, targetType, 100, mustSee, false, selector); // Leaf 500 -> 100 seem doesn't used before
|
||||
}
|
||||
|
||||
public int getCooldown() {
|
||||
@@ -23,6 +23,16 @@ public class NearestHealableRaiderTargetGoal<T extends LivingEntity> extends Nea
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
+ // Leaf start - Async target finding
|
||||
+ if (readyNow) {
|
||||
+ readyNow = false;
|
||||
+ return ((Raider) this.mob).hasActiveRaid();
|
||||
+ }
|
||||
+ // 5 sec
|
||||
+ if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaf end - Async target finding
|
||||
if (this.cooldown > 0 || !this.mob.getRandom().nextBoolean()) {
|
||||
return false;
|
||||
} else if (!((Raider)this.mob).hasActiveRaid()) {
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java
|
||||
index abf57494950f55bbd75f335f26736cb9e703c197..683722fbd07fcae9cdd72928ed25fd084202b57e 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
|
||||
+ 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
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/Sensing.java b/net/minecraft/world/entity/ai/sensing/Sensing.java
|
||||
index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..3f8c18f4040f4929df79ba85906330b150720cb0 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/Sensing.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/Sensing.java
|
||||
@@ -32,9 +32,21 @@ public class Sensing {
|
||||
// Gale end - Petal - reduce line of sight updates - expiring entity id lists
|
||||
}
|
||||
|
||||
+ // Leaf start - async target finding
|
||||
public void tick() {
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ synchronized (this) {
|
||||
+ tick1();
|
||||
+ }
|
||||
+ } else {
|
||||
+ tick1();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void tick1() {
|
||||
+ // Leaf end - async target finding
|
||||
if (this.expiring == null) { // Gale - Petal - reduce line of sight updates
|
||||
- this.seen.clear();
|
||||
+ this.seen.clear();
|
||||
// Gale start - Petal - reduce line of sight updates
|
||||
} else {
|
||||
var expiringNow = this.expiring[this.nextToExpireIndex];
|
||||
@@ -62,7 +74,19 @@ public class Sensing {
|
||||
// Gale end - Petal - reduce line of sight updates
|
||||
}
|
||||
|
||||
+ // Leaf start - async target finding
|
||||
public boolean hasLineOfSight(Entity entity) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
|
||||
+ synchronized (this) {
|
||||
+ return hasLineOfSight1(entity);
|
||||
+ }
|
||||
+ } else {
|
||||
+ return hasLineOfSight1(entity);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private boolean hasLineOfSight1(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..28dbba5494779d82b6ae7c435db0ed76dc5eaf1f 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
|
||||
+ if (serverLevel == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaf end
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,6 +868,13 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaf start - Async target finding
|
||||
+ @Override
|
||||
+ public boolean poll() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaf end - Async target finding
|
||||
+
|
||||
@Override
|
||||
public void start() {
|
||||
this.setTarget(this.trustedLastHurtBy);
|
||||
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index c7897532163d4fdf5a82982f7d24a47dd61e3dfa..914d171c0183f00ff474517e2fa3ec00d7f1d6f1 100644
|
||||
--- a/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -608,6 +608,13 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
this.enderman.setBeingStaredAt();
|
||||
}
|
||||
|
||||
+ // Leaf start - Async target finding
|
||||
+ @Override
|
||||
+ public boolean poll() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaf end - Async target finding
|
||||
+
|
||||
@Override
|
||||
public void stop() {
|
||||
this.pendingTarget = null;
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.dreeam.leaf.async.ai;
|
||||
|
||||
public interface AsyncGoal {
|
||||
boolean poll();
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
package org.dreeam.leaf.async.ai;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AsyncGoalExecutor {
|
||||
public static final java.util.concurrent.ExecutorService EXECUTOR = new ThreadPoolExecutor(
|
||||
1,
|
||||
1,
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(128),
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
.setNameFormat("Leaf Async Target Finding Thread")
|
||||
.setDaemon(true)
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.build(), new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
@Nullable
|
||||
public static java.util.concurrent.ExecutorService EXECUTOR;
|
||||
|
||||
public static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("Leaf Async Entity Lookup");
|
||||
|
||||
public static void runTasks(List<Runnable> tasks) {
|
||||
for (Runnable task : tasks) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.dreeam.leaf.config.modules.async;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class AsyncBlockFinding extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".async-block-finding";
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
public static boolean asyncBlockFindingInitialized;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
config.addCommentRegionBased(getBasePath(), """
|
||||
This moves the expensive search calculations to a background thread while
|
||||
keeping the actual block validation on the main thread.""",
|
||||
"""
|
||||
这会将昂贵的搜索计算移至后台线程, 同时在主线程上保持实际的方块验证.""");
|
||||
|
||||
if (!asyncBlockFindingInitialized) {
|
||||
asyncBlockFindingInitialized = true;
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
|
||||
package org.dreeam.leaf.config.modules.async;
|
||||
|
||||
import org.dreeam.leaf.async.ai.AsyncGoalExecutor;
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AsyncTargetFinding extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
@@ -13,6 +18,11 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
|
||||
@Experimental
|
||||
public static boolean enabled = false;
|
||||
public static boolean alertOther = true;
|
||||
public static boolean searchBlock = false;
|
||||
public static boolean searchEntity = true;
|
||||
public static boolean searchPlayer = false;
|
||||
public static boolean searchPlayerTempt = false;
|
||||
public static boolean asyncTargetFindingInitialized;
|
||||
|
||||
@Override
|
||||
@@ -24,9 +34,35 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
"""
|
||||
这会将昂贵的实体目标搜索计算移至后台线程, 同时在主线程上保持实际的实体验证.""");
|
||||
|
||||
if (!asyncTargetFindingInitialized) {
|
||||
asyncTargetFindingInitialized = true;
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
if (asyncTargetFindingInitialized) {
|
||||
return;
|
||||
}
|
||||
asyncTargetFindingInitialized = true;
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
alertOther = config.getBoolean(getBasePath() + ".async-alert-other", true);
|
||||
searchBlock = config.getBoolean(getBasePath() + ".async-search-block", false);
|
||||
searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true);
|
||||
searchPlayer = config.getBoolean(getBasePath() + ".async-search-player", false);
|
||||
searchPlayerTempt = config.getBoolean(getBasePath() + ".async-search-player-tempt", false);
|
||||
if (!enabled) {
|
||||
alertOther = false;
|
||||
searchEntity = false;
|
||||
searchBlock = false;
|
||||
searchPlayer = false;
|
||||
searchPlayerTempt = false;
|
||||
return;
|
||||
}
|
||||
AsyncGoalExecutor.EXECUTOR = new ThreadPoolExecutor(
|
||||
1,
|
||||
1,
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(128),
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
.setNameFormat("Leaf Async Target Finding Thread")
|
||||
.setDaemon(true)
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user