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:
@@ -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);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user