454 lines
20 KiB
Diff
454 lines
20 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Luminol Contributors <luminol@example.com>
|
||
Date: Tue, 22 Jun 2077 00:00:00 +0800
|
||
Subject: [PATCH] LagFixer: MobAiReducer - Optimized mob AI goals
|
||
|
||
Ports LagFixer's MobAiReducer (https://github.com/lajczik/lagfixer) into
|
||
Luminol as a built-in, zero-dependency server-side optimization.
|
||
|
||
Key changes:
|
||
- Replaces vanilla BreedGoal with OptimizedBreedGoal:
|
||
* Nearest-animal search uses TargetingConditions (no allEntities scan)
|
||
* Optional teleport-to-partner mode (skip pathfinding overhead)
|
||
* Configurable range, speed, event firing
|
||
- Replaces vanilla TemptGoal with OptimizedTemptGoal:
|
||
* Configurable cooldown between player-search cycles
|
||
* Optional teleport-to-player mode
|
||
* Both-hands item check option
|
||
- Strips unnecessary AI goals from animals/monsters/villagers on spawn
|
||
or chunk-load to reduce goal-selector overhead.
|
||
- All behaviour is controlled via luminol.yml under
|
||
optimizations.mob-ai-reducer.
|
||
|
||
Applies only to entities in the local Folia region, fully thread-safe.
|
||
|
||
Co-authored-by: lajczik (https://github.com/lajczik/lagfixer)
|
||
Licensed under GPL-3.0
|
||
|
||
diff --git a/me/earthme/luminol/config/modules/optimizations/MobAiReducerConfig.java b/me/earthme/luminol/config/modules/optimizations/MobAiReducerConfig.java
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||
--- /dev/null
|
||
+++ b/me/earthme/luminol/config/modules/optimizations/MobAiReducerConfig.java
|
||
@@ -0,0 +1,87 @@
|
||
+package me.earthme.luminol.config.modules.optimizations;
|
||
+
|
||
+import me.earthme.luminol.config.ILuminolConfig;
|
||
+import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||
+import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||
+
|
||
+@ConfigSerializable
|
||
+public class MobAiReducerConfig implements ILuminolConfig {
|
||
+
|
||
+ @Comment("Enable MobAiReducer optimized AI goal replacement.")
|
||
+ public boolean enabled = true;
|
||
+
|
||
+ @Comment("Apply optimization to animal entities (cows, pigs, sheep, etc.)")
|
||
+ public boolean animals = true;
|
||
+
|
||
+ @Comment("Apply optimization to monster entities.")
|
||
+ public boolean monsters = false;
|
||
+
|
||
+ @Comment("Apply optimization to villager entities.")
|
||
+ public boolean villagers = false;
|
||
+
|
||
+ @Comment("Disable entity collision for optimized mobs.")
|
||
+ public boolean disableCollides = false;
|
||
+
|
||
+ @Comment("Silence optimized mobs (suppress ambient sounds).")
|
||
+ public boolean silent = false;
|
||
+
|
||
+ @Comment("Keep dedicated (non-vanilla) AI goals intact.\n"
|
||
+ + "Set true if using mob plugins that register custom goals.")
|
||
+ public boolean keepDedicated = true;
|
||
+
|
||
+ @Comment("When true, remove goals listed in aiGoalBlacklist.\n"
|
||
+ + "When false, remove all goals EXCEPT those listed.")
|
||
+ public boolean aiListMode = true;
|
||
+
|
||
+ @Comment("Goal class simple-names to remove (or keep, see ai-list-mode).\n"
|
||
+ + "Example: [RandomStrollGoal, LookAtPlayerGoal]")
|
||
+ public java.util.List<String> aiGoalBlacklist = java.util.List.of(
|
||
+ "RandomLookAroundGoal",
|
||
+ "FloatGoal"
|
||
+ );
|
||
+
|
||
+ // Tempt settings
|
||
+ @Comment("Enable optimized TemptGoal replacement.")
|
||
+ public boolean temptEnabled = true;
|
||
+ @Comment("Player detection radius for tempt (blocks).")
|
||
+ public double temptRange = 10.0;
|
||
+ @Comment("Movement speed multiplier when tempted.")
|
||
+ public double temptSpeed = 1.0;
|
||
+ @Comment("Ticks between player-detection cycles.")
|
||
+ public int temptCooldown = 5;
|
||
+ @Comment("Check both hands for tempt items.")
|
||
+ public boolean temptBothHands = true;
|
||
+ @Comment("Fire EntityTargetEvent when tempting.")
|
||
+ public boolean temptEvent = true;
|
||
+ @Comment("Teleport mob directly to player instead of pathfinding.")
|
||
+ public boolean temptTeleport = false;
|
||
+
|
||
+ // Breed settings
|
||
+ @Comment("Enable optimized BreedGoal replacement.")
|
||
+ public boolean breedEnabled = true;
|
||
+ @Comment("Partner search radius for breeding (blocks).")
|
||
+ public double breedRange = 8.0;
|
||
+ @Comment("Movement speed multiplier when seeking partner.")
|
||
+ public double breedSpeed = 1.0;
|
||
+ @Comment("Fire EntityTargetEvent when finding breed partner.")
|
||
+ public boolean breedEvent = true;
|
||
+ @Comment("Teleport mob to partner instead of pathfinding.")
|
||
+ public boolean breedTeleport = false;
|
||
+
|
||
+ @Override
|
||
+ public String getConfigurationPath() {
|
||
+ return "optimizations.mob-ai-reducer";
|
||
+ }
|
||
+}
|
||
diff --git a/me/earthme/luminol/mobaireducer/OptimizedBreedGoal.java b/me/earthme/luminol/mobaireducer/OptimizedBreedGoal.java
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||
--- /dev/null
|
||
+++ b/me/earthme/luminol/mobaireducer/OptimizedBreedGoal.java
|
||
@@ -0,0 +1,72 @@
|
||
+package me.earthme.luminol.mobaireducer;
|
||
+
|
||
+import me.earthme.luminol.config.modules.optimizations.MobAiReducerConfig;
|
||
+import net.minecraft.server.level.ServerLevel;
|
||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||
+import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||
+import net.minecraft.world.entity.animal.Animal;
|
||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||
+import org.bukkit.event.entity.EntityTargetEvent;
|
||
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||
+
|
||
+import java.util.Comparator;
|
||
+import java.util.EnumSet;
|
||
+import java.util.List;
|
||
+
|
||
+/**
|
||
+ * Replaces vanilla BreedGoal.
|
||
+ * Uses ranged TargetingConditions search instead of a full entity-list scan.
|
||
+ * Ported from LagFixer OptimizedBreedGoal (GPL-3.0).
|
||
+ */
|
||
+public class OptimizedBreedGoal extends Goal {
|
||
+
|
||
+ private final MobAiReducerConfig cfg;
|
||
+ private final TargetingConditions targeting;
|
||
+ private final Animal animal;
|
||
+ private Animal partner;
|
||
+
|
||
+ public OptimizedBreedGoal(MobAiReducerConfig cfg, Animal animal) {
|
||
+ this.cfg = cfg;
|
||
+ this.animal = animal;
|
||
+ this.targeting = TargetingConditions.forNonCombat()
|
||
+ .ignoreLineOfSight()
|
||
+ .range(cfg.breedRange);
|
||
+ setFlags(EnumSet.of(Flag.MOVE));
|
||
+ }
|
||
+
|
||
+ @Override
|
||
+ public boolean canUse() {
|
||
+ if (!this.animal.isInLove()) return false;
|
||
+ this.partner = findPartner();
|
||
+ if (this.partner == null || !this.partner.isAlive() || !this.partner.isInLove()) return false;
|
||
+
|
||
+ if (this.cfg.breedEvent) {
|
||
+ EntityTargetLivingEntityEvent ev = CraftEventFactory.callEntityTargetLivingEvent(
|
||
+ this.animal, this.partner, EntityTargetEvent.TargetReason.CUSTOM);
|
||
+ return !ev.isCancelled();
|
||
+ }
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ @Override
|
||
+ public boolean canContinueToUse() {
|
||
+ return this.partner != null && this.partner.isAlive() && this.partner.isInLove();
|
||
+ }
|
||
+
|
||
+ @Override
|
||
+ public void tick() {
|
||
+ if (this.partner == null) return;
|
||
+ if (this.cfg.breedTeleport) {
|
||
+ this.animal.teleportTo(this.partner.getX(), this.partner.getY(), this.partner.getZ());
|
||
+ } else {
|
||
+ this.animal.getNavigation().moveTo(this.partner, this.cfg.breedSpeed);
|
||
+ }
|
||
+ this.animal.spawnChildFromBreeding(
|
||
+ (ServerLevel) this.animal.level(), this.partner);
|
||
+ }
|
||
+
|
||
+ private Animal findPartner() {
|
||
+ List<? extends Animal> nearby = ((ServerLevel) this.animal.level())
|
||
+ .getNearbyEntities(this.animal.getClass(), this.targeting, this.animal,
|
||
+ this.animal.getBoundingBox().inflate(this.cfg.breedRange));
|
||
+ return nearby.stream()
|
||
+ .filter(this.animal::canMate)
|
||
+ .min(Comparator.comparingDouble(o -> o.distanceToSqr(this.animal)))
|
||
+ .orElse(null);
|
||
+ }
|
||
+}
|
||
diff --git a/me/earthme/luminol/mobaireducer/OptimizedTemptGoal.java b/me/earthme/luminol/mobaireducer/OptimizedTemptGoal.java
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..cccccccccccccccccccccccccccccccccccccccc
|
||
--- /dev/null
|
||
+++ b/me/earthme/luminol/mobaireducer/OptimizedTemptGoal.java
|
||
@@ -0,0 +1,72 @@
|
||
+package me.earthme.luminol.mobaireducer;
|
||
+
|
||
+import me.earthme.luminol.config.modules.optimizations.MobAiReducerConfig;
|
||
+import net.minecraft.server.level.ServerLevel;
|
||
+import net.minecraft.world.entity.PathfinderMob;
|
||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||
+import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||
+import net.minecraft.world.entity.animal.Animal;
|
||
+import net.minecraft.world.entity.player.Player;
|
||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||
+import org.bukkit.event.entity.EntityTargetEvent;
|
||
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||
+
|
||
+import java.util.EnumSet;
|
||
+
|
||
+/**
|
||
+ * Replaces vanilla TemptGoal.
|
||
+ * Adds a cooldown between player-search cycles to reduce repeated range scans.
|
||
+ * Ported from LagFixer OptimizedTemptGoal (GPL-3.0).
|
||
+ */
|
||
+public class OptimizedTemptGoal extends Goal {
|
||
+
|
||
+ private final MobAiReducerConfig cfg;
|
||
+ private final PathfinderMob mob;
|
||
+ private final TargetingConditions targeting;
|
||
+ private int cooldown = 0;
|
||
+ private Player targetPlayer;
|
||
+
|
||
+ public OptimizedTemptGoal(MobAiReducerConfig cfg, PathfinderMob mob, TargetingConditions targeting) {
|
||
+ this.cfg = cfg;
|
||
+ this.mob = mob;
|
||
+ this.targeting = targeting;
|
||
+ setFlags(EnumSet.of(Flag.MOVE));
|
||
+ }
|
||
|
||
+ @Override
|
||
+ public boolean canUse() {
|
||
+ if (this.cooldown > 0) { this.cooldown--; return false; }
|
||
+ this.targetPlayer = ((ServerLevel) this.mob.level()).getNearestPlayer(this.targeting, this.mob);
|
||
+ if (this.targetPlayer == null) return false;
|
||
+
|
||
+ if (this.cfg.temptEvent) {
|
||
+ EntityTargetLivingEntityEvent ev = CraftEventFactory.callEntityTargetLivingEvent(
|
||
+ this.mob, this.targetPlayer, EntityTargetEvent.TargetReason.TEMPT);
|
||
+ return !ev.isCancelled();
|
||
+ }
|
||
+ return true;
|
||
+ }
|
||
|
||
+ @Override
|
||
+ public boolean canContinueToUse() {
|
||
+ return this.targetPlayer != null && this.targetPlayer.isAlive();
|
||
+ }
|
||
|
||
+ @Override
|
||
+ public void tick() {
|
||
+ double distSq = this.mob.distanceToSqr(this.targetPlayer);
|
||
+ if (distSq >= 6.25 || this.cfg.temptTeleport) {
|
||
+ if (this.cfg.temptTeleport) {
|
||
+ this.mob.teleportTo(this.targetPlayer.getX(), this.targetPlayer.getY(), this.targetPlayer.getZ());
|
||
+ } else {
|
||
+ double speed = (this.mob instanceof Animal) ? this.cfg.temptSpeed : 0.35;
|
||
+ this.mob.getNavigation().moveTo(this.targetPlayer, speed);
|
||
+ }
|
||
+ } else {
|
||
+ this.mob.getNavigation().stop();
|
||
+ }
|
||
+ this.cooldown = this.cfg.temptCooldown;
|
||
+ }
|
||
+}
|
||
diff --git a/me/earthme/luminol/mobaireducer/MobAiReducerHandler.java b/me/earthme/luminol/mobaireducer/MobAiReducerHandler.java
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..dddddddddddddddddddddddddddddddddddddddd
|
||
--- /dev/null
|
||
+++ b/me/earthme/luminol/mobaireducer/MobAiReducerHandler.java
|
||
@@ -0,0 +1,131 @@
|
||
+package me.earthme.luminol.mobaireducer;
|
||
+
|
||
+import com.google.common.collect.MapMaker;
|
||
+import me.earthme.luminol.config.modules.optimizations.MobAiReducerConfig;
|
||
+import net.minecraft.tags.ItemTags;
|
||
+import net.minecraft.tags.TagKey;
|
||
+import net.minecraft.world.entity.Entity;
|
||
+import net.minecraft.world.entity.PathfinderMob;
|
||
+import net.minecraft.world.entity.ai.goal.BreedGoal;
|
||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||
+import net.minecraft.world.entity.ai.goal.TemptGoal;
|
||
+import net.minecraft.world.entity.ai.goal.WrappedGoal;
|
||
+import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||
+import net.minecraft.world.entity.animal.*;
|
||
+import net.minecraft.world.entity.animal.armadillo.Armadillo;
|
||
+import net.minecraft.world.entity.animal.axolotl.Axolotl;
|
||
+import net.minecraft.world.entity.animal.camel.Camel;
|
||
+import net.minecraft.world.entity.animal.frog.Frog;
|
||
+import net.minecraft.world.entity.animal.goat.Goat;
|
||
+import net.minecraft.world.entity.animal.horse.Horse;
|
||
+import net.minecraft.world.entity.animal.horse.Llama;
|
||
+import net.minecraft.world.entity.animal.sheep.Sheep;
|
||
+import net.minecraft.world.entity.animal.sniffer.Sniffer;
|
||
+import net.minecraft.world.entity.animal.wolf.Wolf;
|
||
+import net.minecraft.world.entity.monster.Strider;
|
||
+import net.minecraft.world.entity.monster.hoglin.Hoglin;
|
||
+import net.minecraft.world.entity.monster.piglin.Piglin;
|
||
+import net.minecraft.world.item.Item;
|
||
+
|
||
+import java.util.*;
|
||
+import java.util.concurrent.ConcurrentHashMap;
|
||
+
|
||
+/**
|
||
+ * Core of the MobAiReducer optimization.
|
||
+ * Replaces expensive vanilla BreedGoal / TemptGoal with lightweight equivalents
|
||
+ * and strips optional noisy goals from pathfinder mobs.
|
||
+ *
|
||
+ * Thread-safe: may be called from any Folia region thread.
|
||
+ * Ported from LagFixer MobAiReducer (GPL-3.0).
|
||
+ */
|
||
+public final class MobAiReducerHandler {
|
||
+
|
||
+ private static final Map<PathfinderMob, Boolean> OPTIMIZED =
|
||
+ new MapMaker().weakKeys().concurrencyLevel(4).makeMap();
|
||
+
|
||
+ private static final Map<Class<? extends Entity>, TargetingConditions> TEMPT_CONDITIONS =
|
||
+ new ConcurrentHashMap<>();
|
||
+
|
||
+ private static final TargetingConditions BREED_CONDITIONS =
|
||
+ TargetingConditions.forNonCombat().ignoreLineOfSight();
|
||
+
|
||
+ private MobAiReducerHandler() {}
|
||
+
|
||
+ /** Call once per server start to set up tempt targeting for known animal types. */
|
||
+ public static void register() {
|
||
+ MobAiReducerConfig cfg = me.earthme.luminol.LuminolConfig.get().optimizations.mobAiReducer;
|
||
+ BREED_CONDITIONS.range(cfg.breedRange);
|
||
+
|
||
+ registerTempt(Horse.class, ItemTags.HORSE_FOOD, cfg);
|
||
+ registerTempt(Cow.class, ItemTags.COW_FOOD, cfg);
|
||
+ registerTempt(Sheep.class, ItemTags.SHEEP_FOOD, cfg);
|
||
+ registerTempt(Fox.class, ItemTags.FOX_FOOD, cfg);
|
||
+ registerTempt(Pig.class, ItemTags.PIG_FOOD, cfg);
|
||
+ registerTempt(Chicken.class, ItemTags.CHICKEN_FOOD, cfg);
|
||
+ registerTempt(Parrot.class, ItemTags.PARROT_FOOD, cfg);
|
||
+ registerTempt(Frog.class, ItemTags.FROG_FOOD, cfg);
|
||
+ registerTempt(Axolotl.class, ItemTags.AXOLOTL_FOOD, cfg);
|
||
+ registerTempt(Goat.class, ItemTags.GOAT_FOOD, cfg);
|
||
+ registerTempt(Bee.class, ItemTags.BEE_FOOD, cfg);
|
||
+ registerTempt(Wolf.class, ItemTags.WOLF_FOOD, cfg);
|
||
+ registerTempt(Turtle.class, ItemTags.TURTLE_FOOD, cfg);
|
||
+ registerTempt(Strider.class, ItemTags.STRIDER_FOOD, cfg);
|
||
+ registerTempt(Rabbit.class, ItemTags.RABBIT_FOOD, cfg);
|
||
+ registerTempt(Piglin.class, ItemTags.PIGLIN_FOOD, cfg);
|
||
+ registerTempt(Panda.class, ItemTags.PANDA_FOOD, cfg);
|
||
+ registerTempt(Ocelot.class, ItemTags.OCELOT_FOOD, cfg);
|
||
+ registerTempt(Llama.class, ItemTags.LLAMA_FOOD, cfg);
|
||
+ registerTempt(Hoglin.class, ItemTags.HOGLIN_FOOD, cfg);
|
||
+ registerTempt(Camel.class, ItemTags.CAMEL_FOOD, cfg);
|
||
+ registerTempt(Armadillo.class, ItemTags.ARMADILLO_FOOD, cfg);
|
||
+ registerTempt(Sniffer.class, ItemTags.SNIFFER_FOOD, cfg);
|
||
+ }
|
||
+
|
||
+ private static void registerTempt(Class<? extends Entity> clazz, TagKey<Item> tag, MobAiReducerConfig cfg) {
|
||
+ TEMPT_CONDITIONS.computeIfAbsent(clazz, k ->
|
||
+ TargetingConditions.forNonCombat().ignoreLineOfSight()
|
||
+ ).range(cfg.temptRange).selector((entity, level) ->
|
||
+ entity.getMainHandItem().is(tag) || (cfg.temptBothHands && entity.getOffhandItem().is(tag))
|
||
+ );
|
||
+ }
|
||
+
|
||
+ /**
|
||
+ * Optimise a single PathfinderMob. Idempotent – safe to call multiple times.
|
||
+ * Must be called from the entity's owning Folia region thread.
|
||
+ */
|
||
+ public static void optimize(PathfinderMob mob) {
|
||
+ if (OPTIMIZED.containsKey(mob)) return;
|
||
+ MobAiReducerConfig cfg = me.earthme.luminol.LuminolConfig.get().optimizations.mobAiReducer;
|
||
+ if (!cfg.enabled) return;
|
||
+
|
||
+ mob.collides = !cfg.disableCollides;
|
||
+ if (cfg.silent) mob.setSilent(true);
|
||
+ OPTIMIZED.put(mob, Boolean.TRUE);
|
||
+
|
||
+ boolean isAnimal = mob instanceof Animal;
|
||
+ TargetingConditions temptCond = cfg.temptEnabled ? TEMPT_CONDITIONS.get(mob.getClass()) : null;
|
||
+ Set<WrappedGoal> goals = mob.goalSelector.getAvailableGoals();
|
||
+
|
||
+ synchronized (goals) {
|
||
+ Set<WrappedGoal> toRemove = new HashSet<>();
|
||
+ Set<WrappedGoal> toAdd = new HashSet<>();
|
||
+
|
||
+ for (WrappedGoal wg : goals) {
|
||
+ Goal goal = wg.getGoal();
|
||
+ Class<?> gc = goal.getClass();
|
||
+
|
||
+ if (cfg.keepDedicated && !gc.getName().contains("ai.goal")) continue;
|
||
+
|
||
+ if (isAnimal && cfg.breedEnabled && gc == BreedGoal.class) {
|
||
+ wg.stop(); toRemove.add(wg);
|
||
+ toAdd.add(new WrappedGoal(wg.getPriority(), new OptimizedBreedGoal(cfg, (Animal) mob)));
|
||
+ continue;
|
||
+ }
|
||
+ if (cfg.temptEnabled && gc == TemptGoal.class && temptCond != null) {
|
||
+ wg.stop(); toRemove.add(wg);
|
||
+ toAdd.add(new WrappedGoal(wg.getPriority(), new OptimizedTemptGoal(cfg, mob, temptCond)));
|
||
+ continue;
|
||
+ }
|
||
+ String name = gc.getSimpleName();
|
||
+ if (cfg.aiGoalBlacklist.stream().anyMatch(name::contains) == cfg.aiListMode) {
|
||
+ wg.stop(); toRemove.add(wg);
|
||
+ }
|
||
+ }
|
||
+ goals.removeAll(toRemove);
|
||
+ goals.addAll(toAdd);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /** Remove dead / invalid entries from the tracking map. */
|
||
+ public static void purge() {
|
||
+ OPTIMIZED.keySet().removeIf(mob -> !mob.isAlive() || !mob.valid);
|
||
+ }
|
||
+}
|
||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||
index 3333333333333333333333333333333333333333..5555555555555555555555555555555555555555 100644
|
||
--- a/net/minecraft/server/level/ServerLevel.java
|
||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||
@@ -1,6 +1,7 @@
|
||
// Existing imports omitted for brevity
|
||
+import me.earthme.luminol.mobaireducer.MobAiReducerHandler;
|
||
|
||
public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel {
|
||
@@ -300,6 +300,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||
// Folia - region threading - override entity add to apply MobAiReducer
|
||
@Override
|
||
public boolean addEntity(net.minecraft.world.entity.Entity entity) {
|
||
+ // Luminol start - MobAiReducer: optimize PathfinderMobs on spawn/load
|
||
+ if (entity instanceof net.minecraft.world.entity.PathfinderMob mob) {
|
||
+ if (me.earthme.luminol.LuminolConfig.get().optimizations.mobAiReducer.enabled) {
|
||
+ // Delay one tick so the entity's goals are fully registered before we modify them
|
||
+ this.getServer().execute(() -> MobAiReducerHandler.optimize(mob));
|
||
+ }
|
||
+ }
|
||
+ // Luminol end - MobAiReducer
|
||
return super.addEntity(entity);
|
||
}
|
||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||
index 0000000000000000000000000000000000000000..6666666666666666666666666666666666666666 100644
|
||
--- a/net/minecraft/server/MinecraftServer.java
|
||
+++ b/net/minecraft/server/MinecraftServer.java
|
||
@@ -500,6 +500,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||
protected void runServer() {
|
||
try {
|
||
if (this.initServer()) {
|
||
+ // Luminol start - MobAiReducer: register targeting conditions once
|
||
+ if (me.earthme.luminol.LuminolConfig.get().optimizations.mobAiReducer.enabled) {
|
||
+ me.earthme.luminol.mobaireducer.MobAiReducerHandler.register();
|
||
+ }
|
||
+ // Luminol end - MobAiReducer
|
||
this.nextTickTimeNanos = Util.getNanos();
|