From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 16:05:57 +0300 Subject: [PATCH] Optimize entities diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java index 065553a549e54492e8fe42fe7dc61d11ac8da6ef..402955e7042f01bdb8296a43bcca52dbb3a224c1 100644 --- a/net/minecraft/world/entity/AgeableMob.java +++ b/net/minecraft/world/entity/AgeableMob.java @@ -126,6 +126,16 @@ public abstract class AgeableMob extends PathfinderMob { public void onSyncedDataUpdated(EntityDataAccessor key) { if (DATA_BABY_ID.equals(key)) { this.refreshDimensions(); + // DivineMC start - Optimize entities + if (isBaby()) { + org.bxteam.divinemc.util.entity.SensorHelper.enableSensor(this, net.minecraft.world.entity.ai.sensing.SensorType.NEAREST_ADULT, true); + } else { + org.bxteam.divinemc.util.entity.SensorHelper.disableSensor(this, net.minecraft.world.entity.ai.sensing.SensorType.NEAREST_ADULT); + if (this.getBrain().hasMemoryValue(net.minecraft.world.entity.ai.memory.MemoryModuleType.NEAREST_VISIBLE_ADULT)) { + this.getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.NEAREST_VISIBLE_ADULT, java.util.Optional.empty()); + } + } + // DivineMC end - Optimize entities } super.onSyncedDataUpdated(key); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java index 79d224baca372cb1b6b89f7fcb63c5fe3707adb5..b5004de3ca8951a5884a3b62b129aa2588a67af7 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -1712,6 +1712,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name private int checkInsideBlocks(Vec3 from, Vec3 to, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, LongSet visited, int maxSteps) { AABB aabb = this.makeBoundingBox(to).deflate(1.0E-5F); + // DivineMC start - Optimize entities + final net.minecraft.world.level.chunk.ChunkAccess[] cachedChunk = new net.minecraft.world.level.chunk.ChunkAccess[] { null }; + final long[] lastChunkPos = { Long.MIN_VALUE }; + // DivineMC end - Optimize entities boolean flag = from.distanceToSqr(to) > Mth.square(0.9999900000002526); boolean flag1 = this.level instanceof ServerLevel serverLevel && serverLevel.getServer().debugSubscribers().hasAnySubscriberFor(DebugSubscriptions.ENTITY_BLOCK_INTERSECTIONS); @@ -1727,7 +1731,21 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name return false; } else { atomicInteger.set(index); - BlockState blockState = this.level().getBlockState(pos); + // DivineMC start - Optimize entities + final int chunkX = pos.getX() >> 4; + final int chunkZ = pos.getZ() >> 4; + final long chunkLongPos = ((long) chunkZ << 32) | (chunkX & 0xFFFFFFFFL); + if (lastChunkPos[0] != chunkLongPos) { + // update cache, this is a different chunk than previous + lastChunkPos[0] = chunkLongPos; + cachedChunk[0] = this.level.getChunkIfLoaded(chunkX, chunkZ); + } + net.minecraft.world.level.chunk.ChunkAccess chunk = cachedChunk[0]; + if (chunk == null) { + return true; + } + BlockState blockState = chunk.getBlockState(pos); + // DivineMC end - Optimize entities if (blockState.isAir()) { if (flag1) { this.debugBlockIntersection((ServerLevel)this.level(), pos.immutable(), false, false); diff --git a/net/minecraft/world/entity/InsideBlockEffectApplier.java b/net/minecraft/world/entity/InsideBlockEffectApplier.java index a7bc5ead2062504ceac95f603bc1ca8d4290bbfd..533c790ce305043f53c76f03a12676c567118a44 100644 --- a/net/minecraft/world/entity/InsideBlockEffectApplier.java +++ b/net/minecraft/world/entity/InsideBlockEffectApplier.java @@ -31,68 +31,115 @@ public interface InsideBlockEffectApplier { public static class StepBasedCollector implements InsideBlockEffectApplier { private static final InsideBlockEffectType[] APPLY_ORDER = InsideBlockEffectType.values(); - private static final int NO_STEP = -1; - private final Map> effectsInStep = new java.util.EnumMap<>(InsideBlockEffectType.class); // Paper - track position inside effect was triggered on - private final Map>> beforeEffectsInStep = Util.makeEnumMap( - InsideBlockEffectType.class, insideBlockEffectType -> new ArrayList<>() - ); - private final Map>> afterEffectsInStep = Util.makeEnumMap( - InsideBlockEffectType.class, insideBlockEffectType -> new ArrayList<>() - ); - private final List> finalEffects = new ArrayList<>(); + // DivineMC start - Optimize entities + private final Consumer[] effectsInStep = new Consumer[APPLY_ORDER.length]; + private final it.unimi.dsi.fastutil.objects.ObjectArrayList>[] beforeEffectsInStep = new it.unimi.dsi.fastutil.objects.ObjectArrayList[APPLY_ORDER.length]; + private final it.unimi.dsi.fastutil.objects.ObjectArrayList>[] afterEffectsInStep = new it.unimi.dsi.fastutil.objects.ObjectArrayList[APPLY_ORDER.length]; + private final it.unimi.dsi.fastutil.objects.ObjectArrayList> finalEffects = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); + // DivineMC end - Optimize entities private int lastStep = -1; - public void advanceStep(int step, net.minecraft.core.BlockPos pos) { // Paper - track position inside effect was triggered on - this.currentBlockPos = pos; // Paper - track position inside effect was triggered on + // DivineMC start - Optimize entities + public StepBasedCollector() { + for (int i = 0; i < APPLY_ORDER.length; i++) { + beforeEffectsInStep[i] = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(2); + afterEffectsInStep[i] = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(2); + } + } + + public void advanceStep(int step, net.minecraft.core.BlockPos pos) { + this.currentBlockPos = pos; if (this.lastStep != step) { this.lastStep = step; this.flushStep(); } } + // DivineMC end - Optimize entities public void applyAndClear(Entity entity) { this.flushStep(); - for (Consumer consumer : this.finalEffects) { + // DivineMC start - Optimize entities + List> effects = this.finalEffects; + int size = effects.size(); + + if (size == 0) { + this.lastStep = -1; + return; + } + + if (!entity.isAlive()) { + effects.clear(); + this.lastStep = -1; + return; + } + + int i = 0; + while (i < size - 3) { + effects.get(i++).accept(entity); + effects.get(i++).accept(entity); + effects.get(i++).accept(entity); + effects.get(i++).accept(entity); if (!entity.isAlive()) { break; } + } - consumer.accept(entity); + if (entity.isAlive()) { + for (; i < size; i++) { + effects.get(i).accept(entity); + if (!entity.isAlive()) { + break; + } + } } - this.finalEffects.clear(); + effects.clear(); + // DivineMC end - Optimize entities this.lastStep = -1; } private void flushStep() { - for (InsideBlockEffectType insideBlockEffectType : APPLY_ORDER) { - List> list = this.beforeEffectsInStep.get(insideBlockEffectType); - this.finalEffects.addAll(list); - list.clear(); - if (this.effectsInStep.remove(insideBlockEffectType) instanceof final Consumer recordedEffect) { // Paper - track position inside effect was triggered on - better than null check to avoid diff. - this.finalEffects.add(recordedEffect); // Paper - track position inside effect was triggered on + // DivineMC start - Optimize entities + final int len = APPLY_ORDER.length; + final Consumer[] effectArr = this.effectsInStep; + final List> finalList = this.finalEffects; + + for (int i = 0; i < len; i++) { + List> beforeList = this.beforeEffectsInStep[i]; + if (!beforeList.isEmpty()) { + finalList.addAll(beforeList); + beforeList.clear(); } - List> list1 = this.afterEffectsInStep.get(insideBlockEffectType); - this.finalEffects.addAll(list1); - list1.clear(); + Consumer effect = effectArr[i]; + if (effect != null) { + finalList.add(effect); + effectArr[i] = null; + } + + List> afterList = this.afterEffectsInStep[i]; + if (!afterList.isEmpty()) { + finalList.addAll(afterList); + afterList.clear(); + } } + // DivineMC end - Optimize entities } @Override public void apply(InsideBlockEffectType type) { - this.effectsInStep.put(type, recorded(type)); // Paper - track position inside effect was triggered on + effectsInStep[type.ordinal()] = recorded(type); // DivineMC - Optimize entities } @Override public void runBefore(InsideBlockEffectType type, Consumer effect) { - this.beforeEffectsInStep.get(type).add(effect); + beforeEffectsInStep[type.ordinal()].add(effect); // DivineMC - Optimize entities } @Override public void runAfter(InsideBlockEffectType type, Consumer effect) { - this.afterEffectsInStep.get(type).add(effect); + afterEffectsInStep[type.ordinal()].add(effect); // DivineMC - Optimize entities } // Paper start - track position inside effect was triggered on diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java index 9ccddcb9a3df8fd9e769069b4502c4422872c562..a05df4dfa6b5078558ef9d6603297298a3e10c3d 100644 --- a/net/minecraft/world/entity/ai/Brain.java +++ b/net/minecraft/world/entity/ai/Brain.java @@ -45,16 +45,75 @@ public class Brain { static final Logger LOGGER = LogUtils.getLogger(); private final Supplier>> codec; private static final int SCHEDULE_UPDATE_DELAY = 20; - private final Map, Optional>> memories = Maps.newHashMap(); - public final Map>, Sensor> sensors = Maps.newLinkedHashMap(); + // DivineMC start - Optimize entities + private Map, Optional>> memories = Maps.newConcurrentMap(); + public Map>, Sensor> sensors = Maps.newLinkedHashMap(); private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); private Schedule schedule = Schedule.EMPTY; - private final Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); + private Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); + // DivineMC end - Optimize entities private final Map>> activityMemoriesToEraseWhenStopped = Maps.newHashMap(); private Set coreActivities = Sets.newHashSet(); private final Set activeActivities = Sets.newHashSet(); private Activity defaultActivity = Activity.IDLE; private long lastScheduleUpdate = -9999L; + // DivineMC start - Optimize entities + private java.util.ArrayList> possibleTasks; + private org.bxteam.divinemc.util.collections.MaskedList> runningTasks; + + private void onTasksChanged() { + this.runningTasks = null; + this.onPossibleActivitiesChanged(); + } + + private void onPossibleActivitiesChanged() { + this.possibleTasks = null; + } + + private void initPossibleTasks() { + this.possibleTasks = new java.util.ArrayList<>(); + for (Map>> map : this.availableBehaviorsByPriority.values()) { + for (Map.Entry>> entry : map.entrySet()) { + Activity activity = entry.getKey(); + if (!this.activeActivities.contains(activity)) { + continue; + } + Set> set = entry.getValue(); + for (BehaviorControl task : set) { + //noinspection UseBulkOperation + this.possibleTasks.add(task); + } + } + } + } + + private java.util.ArrayList> getPossibleTasks() { + if (this.possibleTasks == null) { + this.initPossibleTasks(); + } + return this.possibleTasks; + } + + private org.bxteam.divinemc.util.collections.MaskedList> getCurrentlyRunningTasks() { + if (this.runningTasks == null) { + this.initCurrentlyRunningTasks(); + } + return this.runningTasks; + } + + private void initCurrentlyRunningTasks() { + org.bxteam.divinemc.util.collections.MaskedList> list = new org.bxteam.divinemc.util.collections.MaskedList<>(new ObjectArrayList<>(), false); + + for (Map>> map : this.availableBehaviorsByPriority.values()) { + for (Set> set : map.values()) { + for (BehaviorControl task : set) { + list.addOrSet(task, task.getStatus() == Behavior.Status.RUNNING); + } + } + } + this.runningTasks = list; + } + // DivineMC end - Optimize entities public static Brain.Provider provider( Collection> memoryTypes, Collection>> sensorTypes @@ -146,6 +205,12 @@ public class Brain { for (Brain.MemoryValue memoryValue : memoryValues) { memoryValue.setMemoryInternal(this); } + // DivineMC start - Optimize entities + this.onTasksChanged(); + this.memories = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(this.memories); + this.sensors = new it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap<>(this.sensors); + this.activityRequirements = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.activityRequirements); + // DivineMC end - Optimize entities } public DataResult serializeStart(DynamicOps ops) { @@ -165,6 +230,7 @@ public class Brain { } public void eraseMemory(MemoryModuleType type) { + if (!this.memories.containsKey(type)) return; // DivineMC - Optimize entities this.setMemory(type, Optional.empty()); } @@ -180,16 +246,33 @@ public class Brain { this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of)); } + // DivineMC start - Optimize entities void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { + if (memory.isPresent() && this.isEmptyCollection(memory.get().getValue())) { + this.eraseMemory(memoryType); + return; + } + if (this.memories.containsKey(memoryType)) { - if (memory.isPresent() && this.isEmptyCollection(memory.get().getValue())) { - this.eraseMemory(memoryType); - } else { - this.memories.put(memoryType, memory); - } + this.increaseMemoryModificationCount(this.memories, memoryType, memory); } } + private long memoryModCount = 1; + + public long getMemoryModCount() { + return memoryModCount; + } + + private Object increaseMemoryModificationCount(Map map, T key, A newValue) { + Object oldValue = map.put(key, newValue); + if (oldValue == null || ((Optional) oldValue).isPresent() != ((Optional) newValue).isPresent()) { + this.memoryModCount++; + } + return oldValue; + } + // DivineMC end - Optimize entities + public Optional getMemory(MemoryModuleType type) { Optional> optional = this.memories.get(type); if (optional == null) { @@ -251,19 +334,7 @@ public class Brain { @Deprecated @VisibleForDebug public List> getRunningBehaviors() { - List> list = new ObjectArrayList<>(); - - for (Map>> map : this.availableBehaviorsByPriority.values()) { - for (Set> set : map.values()) { - for (BehaviorControl behaviorControl : set) { - if (behaviorControl.getStatus() == Behavior.Status.RUNNING) { - list.add(behaviorControl); - } - } - } - } - - return list; + return this.getCurrentlyRunningTasks(); // DivineMC - Optimize entities } public void useDefaultActivity() { @@ -294,6 +365,7 @@ public class Brain { this.activeActivities.clear(); this.activeActivities.addAll(this.coreActivities); this.activeActivities.add(activity); + this.onPossibleActivitiesChanged(); // DivineMC - Optimize entities } } @@ -383,11 +455,13 @@ public class Brain { .computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet()) .add((BehaviorControl)pair.getSecond()); } + this.onTasksChanged(); // DivineMC - Optimize entities } @VisibleForTesting public void removeAllBehaviors() { this.availableBehaviorsByPriority.clear(); + this.onTasksChanged(); // DivineMC - Optimize entities } public boolean isActive(Activity activity) { @@ -404,6 +478,7 @@ public class Brain { } } + brain.memoryModCount = this.memoryModCount + 1; // DivineMC - Optimize entities return brain; } @@ -438,31 +513,38 @@ public class Brain { for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.doStop(level, owner, gameTime); + // DivineMC start - Optimize entities + if (this.runningTasks != null) { + this.runningTasks.setVisible(behaviorControl, false); + } + // DivineMC end - Optimize entities } } + // DivineMC start - Optimize entities private void startEachNonRunningBehavior(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (Map>> map : this.availableBehaviorsByPriority.values()) { - for (Entry>> entry : map.entrySet()) { - Activity activity = entry.getKey(); - if (this.activeActivities.contains(activity)) { - for (BehaviorControl behaviorControl : entry.getValue()) { - if (behaviorControl.getStatus() == Behavior.Status.STOPPED) { - behaviorControl.tryStart(level, entity, gameTime); - } - } + long startTime = level.getGameTime(); + for (BehaviorControl task : this.getPossibleTasks()) { + if (task.getStatus() == Behavior.Status.STOPPED) { + task.tryStart(level, entity, startTime); + if (this.runningTasks != null && task.getStatus() == Behavior.Status.RUNNING) { + this.runningTasks.setVisible(task, true); } } } } + // DivineMC end - Optimize entities private void tickEachRunningBehavior(ServerLevel level, E entity) { long gameTime = level.getGameTime(); for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.tickOrStop(level, entity, gameTime); + // DivineMC start - Optimize entities + if (this.runningTasks != null && behaviorControl.getStatus() != Behavior.Status.RUNNING) { + this.runningTasks.setVisible(behaviorControl, false); + } + // DivineMC end - Optimize entities } } diff --git a/net/minecraft/world/entity/ai/behavior/Behavior.java b/net/minecraft/world/entity/ai/behavior/Behavior.java index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..02508662c722a515cfd78f872c8ba8bbffd8b6fb 100644 --- a/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/net/minecraft/world/entity/ai/behavior/Behavior.java @@ -14,6 +14,10 @@ public abstract class Behavior implements BehaviorContro private long endTimestamp; private final int minDuration; private final int maxDuration; + // DivineMC start - Optimize entities + private long cachedMemoryModCount = -1; + private boolean cachedHasRequiredMemoryState; + // DivineMC end - Optimize entities private final String configKey; // Paper - configurable behavior tick rate and timings public Behavior(Map, MemoryStatus> entryCondition) { @@ -27,7 +31,7 @@ public abstract class Behavior implements BehaviorContro public Behavior(Map, MemoryStatus> entryCondition, int minDuration, int maxDuration) { this.minDuration = minDuration; this.maxDuration = maxDuration; - this.entryCondition = entryCondition; + this.entryCondition = new it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<>(entryCondition); // DivineMC - Optimize entities - Use fastutil // Paper start - configurable behavior tick rate and timings String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); int lastSeparator = key.lastIndexOf('.'); @@ -103,17 +107,26 @@ public abstract class Behavior implements BehaviorContro return this.getClass().getSimpleName(); } - protected boolean hasRequiredMemories(E owner) { - for (Entry, MemoryStatus> entry : this.entryCondition.entrySet()) { - MemoryModuleType memoryModuleType = entry.getKey(); - MemoryStatus memoryStatus = entry.getValue(); - if (!owner.getBrain().checkMemory(memoryModuleType, memoryStatus)) { - return false; + // DivineMC start - Optimize entities + public boolean hasRequiredMemories(E entity) { + net.minecraft.world.entity.ai.Brain brain = entity.getBrain(); + long modCount = brain.getMemoryModCount(); + if (this.cachedMemoryModCount == modCount) { + return this.cachedHasRequiredMemoryState; + } + this.cachedMemoryModCount = modCount; + + it.unimi.dsi.fastutil.objects.ObjectIterator, net.minecraft.world.entity.ai.memory.MemoryStatus>> fastIterator = ((it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap, net.minecraft.world.entity.ai.memory.MemoryStatus>) this.entryCondition).reference2ObjectEntrySet().fastIterator(); + while (fastIterator.hasNext()) { + it.unimi.dsi.fastutil.objects.Reference2ObjectMap.Entry, MemoryStatus> entry = fastIterator.next(); + if (!brain.checkMemory(entry.getKey(), entry.getValue())) { + return this.cachedHasRequiredMemoryState = false; } } - return true; + return this.cachedHasRequiredMemoryState = true; } + // DivineMC end - Optimize entities public static enum Status { STOPPED, diff --git a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java index 977afa268838304abdb34be253ca36ac1c22e99f..9fdb2ce7b72d0a10c2148027990a0048ca93f976 100644 --- a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java +++ b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java @@ -119,6 +119,12 @@ public class LongJumpToRandomPos extends Behavior { int x = blockPos.getX(); int y = blockPos.getY(); int z = blockPos.getZ(); + // DivineMC start - Optimize entities + if (this.maxLongJumpWidth < 128 && this.maxLongJumpHeight < 128) { + this.jumpCandidates = org.bxteam.divinemc.util.collections.LongJumpChoiceList.forCenter(blockPos, (byte) this.maxLongJumpWidth, (byte) this.maxLongJumpHeight); + return; + } + // DivineMC end - Optimize entities this.jumpCandidates = BlockPos.betweenClosedStream( x - this.maxLongJumpWidth, y - this.maxLongJumpHeight, @@ -174,12 +180,25 @@ public class LongJumpToRandomPos extends Behavior { } } + // DivineMC start - Optimize entities protected Optional getJumpCandidate(ServerLevel level) { - Optional randomItem = WeightedRandom.getRandomItem( - level.random, this.jumpCandidates, LongJumpToRandomPos.PossibleJump::weight - ); - randomItem.ifPresent(this.jumpCandidates::remove); - return randomItem; + Optional optional = getRandomFast(level.random, this.jumpCandidates); + skipRemoveIfAlreadyRemoved(optional, this.jumpCandidates::remove); + return optional; + } + + private Optional getRandomFast(net.minecraft.util.RandomSource random, List pool) { + if (pool instanceof org.bxteam.divinemc.util.collections.LongJumpChoiceList longJumpChoiceList) { + return Optional.ofNullable(longJumpChoiceList.removeRandomWeightedByDistanceSq(random)); + } else { + return WeightedRandom.getRandomItem(random, pool, LongJumpToRandomPos.PossibleJump::weight); + } + } + + private void skipRemoveIfAlreadyRemoved(Optional result, java.util.function.Consumer removeAction) { + if (!(this.jumpCandidates instanceof org.bxteam.divinemc.util.collections.LongJumpChoiceList)) { + result.ifPresent(removeAction); + } } private boolean isAcceptableLandingPosition(ServerLevel level, E entity, BlockPos pos) { diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..dfc62772d5617f0dce72b45a1bebf1b2f051efd5 100644 --- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java +++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java @@ -17,10 +17,10 @@ public class NearestLivingEntitySensor extends Sensor protected void doTick(ServerLevel level, T entity) { double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE); AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue); - List entitiesOfClass = level.getEntitiesOfClass( + it.unimi.dsi.fastutil.objects.ObjectArrayList entitiesOfClass = (it.unimi.dsi.fastutil.objects.ObjectArrayList) level.getEntitiesOfClass( // DivineMC - Optimize collections LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive() ); - entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr)); + entitiesOfClass.unstableSort(Comparator.comparingDouble(entity::distanceToSqr)); // DivineMC - Optimize collections Brain brain = entity.getBrain(); brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, entitiesOfClass); brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, entitiesOfClass)); diff --git a/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java b/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java index 24d1928445b5571e040a2b12d5c82e77a880d9bd..dac0a23aebf2dea1972c07d5c82079da7c9837ac 100644 --- a/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java +++ b/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java @@ -21,9 +21,22 @@ public class VillagerBabiesSensor extends Sensor { entity.getBrain().setMemory(MemoryModuleType.VISIBLE_VILLAGER_BABIES, this.getNearestVillagerBabies(entity)); } + // DivineMC start - Optimize baby villager sensor private List getNearestVillagerBabies(LivingEntity livingEntity) { - return ImmutableList.copyOf(this.getVisibleEntities(livingEntity).findAll(this::isVillagerBaby)); + NearestVisibleLivingEntities visibleEntities = this.getVisibleEntities(livingEntity); + ImmutableList.Builder babies = ImmutableList.builder(); + + for (LivingEntity target : visibleEntities.nearbyEntities) { + if (target.getType() == EntityType.VILLAGER + && target.isBaby() + && visibleEntities.lineOfSightTest.test(target)) { + babies.add(target); + } + } + + return babies.build(); } + // DivineMC end - Optimize baby villager sensor private boolean isVillagerBaby(LivingEntity livingEntity) { return livingEntity.getType() == EntityType.VILLAGER && livingEntity.isBaby(); diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java index 80714e2a6e74047af89680c261e2dbc097d86062..73fe7a8c216aed7dc2274fd53fb126d85ec5137d 100644 --- a/net/minecraft/world/entity/animal/goat/Goat.java +++ b/net/minecraft/world/entity/animal/goat/Goat.java @@ -99,6 +99,13 @@ public class Goat extends Animal { this.getNavigation().setCanFloat(true); this.setPathfindingMalus(PathType.POWDER_SNOW, -1.0F); this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F); + // DivineMC start - Optimize entities + if (!this.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM)) { + org.bxteam.divinemc.util.entity.SensorHelper.disableSensor(this, SensorType.NEAREST_ITEMS); + } else if (net.minecraft.SharedConstants.IS_RUNNING_IN_IDE) { + throw new IllegalStateException("Goat Entity has a nearest visible wanted item memory module! This patch(Optimize-Brain, Goat.java changes) should probably be removed permanently!"); + } + // DivineMC end - Optimize entities } public ItemStack createHorn() { diff --git a/net/minecraft/world/entity/schedule/Activity.java b/net/minecraft/world/entity/schedule/Activity.java index 5a143bb6fabba3dc4e2272afb0be636d5722ea22..133a51ed45500aba7b0bc4a7acb19731a524d8c1 100644 --- a/net/minecraft/world/entity/schedule/Activity.java +++ b/net/minecraft/world/entity/schedule/Activity.java @@ -32,10 +32,12 @@ public class Activity { public static final Activity DIG = register("dig"); private final String name; private final int hashCode; + public final int id; // DivineMC - Optimize entities - cache registry ID - private Activity(String name) { + private Activity(String name, int id) { this.name = name; this.hashCode = name.hashCode(); + this.id = id; // DivineMC - Optimize entities - cache registry ID } public String getName() { @@ -43,7 +45,7 @@ public class Activity { } private static Activity register(String key) { - return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key)); + return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key, BuiltInRegistries.ACTIVITY.size())); // DivineMC - Optimize entities - cache registry ID } @Override