9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00

Use ActivationList on runningBehaviours

This commit is contained in:
Taiyou06
2025-06-08 00:15:07 +02:00
parent da48e6e0fb
commit acf2c14f80
2 changed files with 315 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <kaandindar21@gmail.com>
Date: Sat, 7 Jun 2025 23:22:56 +0200
Subject: [PATCH] Use ActivationList on runningBehaviors
diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java
index 34b66ee67927bc0796d6c5f069393618abca9d74..f7dd07feea8884c686e78becb1f9cbd0d2769915 100644
--- a/net/minecraft/world/entity/ai/Brain.java
+++ b/net/minecraft/world/entity/ai/Brain.java
@@ -61,6 +61,7 @@ public class Brain<E extends LivingEntity> {
private long lastScheduleUpdate = -9999L;
private ObjectArrayList<BehaviorControl<? super E>> cachedPotentialBehaviors;
+ private org.dreeam.leaf.util.list.ActivationList<BehaviorControl<? super E>> runningBehaviors;
public static <E extends LivingEntity> Brain.Provider<E> provider(
Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes
) {
@@ -273,19 +274,7 @@ public class Brain<E extends LivingEntity> {
@Deprecated
@VisibleForDebug
public List<BehaviorControl<? super E>> getRunningBehaviors() {
- List<BehaviorControl<? super E>> list = new ObjectArrayList<>();
-
- for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
- for (Set<BehaviorControl<? super E>> set : map.values()) {
- for (BehaviorControl<? super E> behaviorControl : set) {
- if (behaviorControl.getStatus() == Behavior.Status.RUNNING) {
- list.add(behaviorControl);
- }
- }
- }
- }
-
- return list;
+ return this.getRunningBehaviorsList();
}
public void useDefaultActivity() {
@@ -453,12 +442,14 @@ public class Brain<E extends LivingEntity> {
long gameTime = owner.level().getGameTime();
for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
+ this.getRunningBehaviorsList().setVisibility(behaviorControl, false);
behaviorControl.doStop(level, owner, gameTime);
}
}
private void invalidateBehaviorCache() {
this.cachedPotentialBehaviors = null;
+ this.runningBehaviors = null;
}
private void rebuildBehaviorCache() {
@@ -476,6 +467,25 @@ public class Brain<E extends LivingEntity> {
}
}
+ private void initializeRunningBehaviors() {
+ this.runningBehaviors = new org.dreeam.leaf.util.list.ActivationList<>(false);
+
+ for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
+ for (Set<BehaviorControl<? super E>> set : map.values()) {
+ for (BehaviorControl<? super E> task : set) {
+ this.runningBehaviors.addOrUpdate(task, task.getStatus() == Behavior.Status.RUNNING);
+ }
+ }
+ }
+ }
+
+ private org.dreeam.leaf.util.list.ActivationList<BehaviorControl<? super E>> getRunningBehaviorsList() {
+ if (this.runningBehaviors == null) {
+ this.initializeRunningBehaviors();
+ }
+ return this.runningBehaviors;
+ }
+
private ObjectArrayList<BehaviorControl<? super E>> getPotentialBehaviors() {
if (this.cachedPotentialBehaviors == null) {
this.rebuildBehaviorCache();
@@ -489,6 +499,9 @@ public class Brain<E extends LivingEntity> {
for (BehaviorControl<? super E> task : this.getPotentialBehaviors()) {
if (task.getStatus() == Behavior.Status.STOPPED) {
task.tryStart(level, entity, startTime);
+ if (task.getStatus() == Behavior.Status.RUNNING) {
+ this.getRunningBehaviorsList().setVisibility(task, true);
+ }
}
}
}
@@ -498,6 +511,9 @@ public class Brain<E extends LivingEntity> {
for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
behaviorControl.tickOrStop(level, entity, gameTime);
+ if (behaviorControl.getStatus() != Behavior.Status.RUNNING) {
+ this.getRunningBehaviorsList().setVisibility(behaviorControl, false);
+ }
}
}

View File

@@ -0,0 +1,215 @@
package org.dreeam.leaf.util.list;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.AbstractList;
import java.util.BitSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.function.Consumer;
/**
* A specialized list that allows for efficient hiding and showing of elements
* without physically removing them from the backing store.
* <p>
* Iteration only processes "visible" elements, and visibility can be toggled in O(1) time.
* This is useful for managing lists of tasks or objects where a large set exists,
* but only a small subset is active at any given time.
*
* @param <E> The type of elements in this list.
*/
public class ActivationList<E> extends AbstractList<E> {
private final ObjectArrayList<E> elements;
private final BitSet visibilityMask;
private final Object2IntOpenHashMap<E> elementToIndexMap;
private final boolean isVisibleByDefault;
private int removedSlotCount;
/**
* Constructs a new, empty MaskedList.
*
* @param isVisibleByDefault The default visibility for elements added to this list.
*/
public ActivationList(boolean isVisibleByDefault) {
this.elements = new ObjectArrayList<>();
this.visibilityMask = new BitSet();
this.elementToIndexMap = new Object2IntOpenHashMap<>();
this.elementToIndexMap.defaultReturnValue(-1);
this.isVisibleByDefault = isVisibleByDefault;
}
/**
* Constructs a new, empty MaskedList with default visibility set to true.
*/
public ActivationList() {
this(true);
}
/**
* Adds an element to the list or, if it already exists, updates its visibility.
*
* @param element The element to add or update.
* @param visible The desired visibility of the element.
*/
public void addOrUpdate(E element, boolean visible) {
int index = this.elementToIndexMap.getInt(element);
if (index == -1) {
index = this.elements.size();
this.elements.add(element);
this.elementToIndexMap.put(element, index);
}
this.visibilityMask.set(index, visible);
}
/**
* Sets the visibility of an existing element.
*
* @param element The element whose visibility to change.
* @param visible True to make the element visible, false to hide it.
*/
public void setVisibility(E element, boolean visible) {
int index = this.elementToIndexMap.getInt(element);
if (index != -1) {
this.visibilityMask.set(index, visible);
}
}
@Override
public boolean add(E element) {
if (this.elementToIndexMap.containsKey(element)) {
throw new IllegalArgumentException("MaskedList cannot contain duplicate elements: " + element);
}
this.addOrUpdate(element, this.isVisibleByDefault);
return true;
}
@Override
public boolean remove(Object o) {
int index = this.elementToIndexMap.removeInt(o);
if (index == -1) {
return false;
}
this.visibilityMask.clear(index);
this.elements.set(index, null);
this.removedSlotCount++;
if (this.removedSlotCount > 0 && this.removedSlotCount * 2 >= this.elements.size()) {
compact();
}
return true;
}
/**
* Rebuilds the internal list (wow)
*/
private void compact() {
int writeIndex = 0;
for (int readIndex = 0; readIndex < this.elements.size(); readIndex++) {
E element = this.elements.get(readIndex);
if (element != null) {
if (readIndex != writeIndex) {
this.elements.set(writeIndex, element);
this.elementToIndexMap.put(element, writeIndex);
this.visibilityMask.set(writeIndex, this.visibilityMask.get(readIndex));
}
writeIndex++;
}
}
int oldSize = this.elements.size();
if (writeIndex < oldSize) {
this.elements.removeElements(writeIndex, oldSize);
this.visibilityMask.clear(writeIndex, oldSize);
}
this.removedSlotCount = 0;
}
@Override
public int size() {
return this.visibilityMask.cardinality();
}
@Override
public E get(int index) {
if (index < 0 || index >= this.size()) {
throw new IndexOutOfBoundsException("Index: " + index + ", Visible Size: " + this.size());
}
int setBitIndex = -1;
for (int i = 0; i <= index; i++) {
setBitIndex = this.visibilityMask.nextSetBit(setBitIndex + 1);
}
return this.elements.get(setBitIndex);
}
@Override
public Iterator<E> iterator() {
return new MaskedIterator();
}
private class MaskedIterator implements Iterator<E> {
private int nextVisibleIndex;
MaskedIterator() {
this.nextVisibleIndex = ActivationList.this.visibilityMask.nextSetBit(0);
}
@Override
public boolean hasNext() {
return this.nextVisibleIndex != -1;
}
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
E element = ActivationList.this.elements.get(this.nextVisibleIndex);
this.nextVisibleIndex = ActivationList.this.visibilityMask.nextSetBit(this.nextVisibleIndex + 1);
return element;
}
}
@Override
public Spliterator<E> spliterator() {
return new MaskedSpliterator();
}
private class MaskedSpliterator implements Spliterator<E> {
private int currentIndex;
MaskedSpliterator() {
this.currentIndex = ActivationList.this.visibilityMask.nextSetBit(0);
}
@Override
public boolean tryAdvance(Consumer<? super E> action) {
if (this.currentIndex != -1) {
action.accept(ActivationList.this.elements.get(this.currentIndex));
this.currentIndex = ActivationList.this.visibilityMask.nextSetBit(this.currentIndex + 1);
return true;
}
return false;
}
@Override
public Spliterator<E> trySplit() {
return null; // This spliterator does not support splitting.
}
@Override
public long estimateSize() {
return ActivationList.this.size();
}
@Override
public int characteristics() {
return Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.SIZED;
}
}
}