2025-11-24 22:52:51 +03:00

486 lines
23 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.google.common.annotations.VisibleForTesting
* com.google.common.collect.ImmutableList
* com.google.common.collect.ImmutableList$Builder
* com.google.common.collect.ImmutableSet
* com.google.common.collect.Maps
* com.google.common.collect.Sets
* com.mojang.datafixers.util.Pair
* com.mojang.logging.LogUtils
* com.mojang.serialization.Codec
* com.mojang.serialization.DataResult
* com.mojang.serialization.Dynamic
* com.mojang.serialization.DynamicOps
* com.mojang.serialization.MapCodec
* com.mojang.serialization.MapLike
* com.mojang.serialization.RecordBuilder
* it.unimi.dsi.fastutil.objects.ObjectArrayList
* org.apache.commons.lang3.mutable.MutableObject
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package net.minecraft.world.entity.ai;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.MapLike;
import com.mojang.serialization.RecordBuilder;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.VisibleForDebug;
import net.minecraft.world.attribute.EnvironmentAttribute;
import net.minecraft.world.attribute.EnvironmentAttributeSystem;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.entity.ai.behavior.BehaviorControl;
import net.minecraft.world.entity.ai.memory.ExpirableValue;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.ai.sensing.Sensor;
import net.minecraft.world.entity.ai.sensing.SensorType;
import net.minecraft.world.entity.schedule.Activity;
import net.minecraft.world.phys.Vec3;
import org.apache.commons.lang3.mutable.MutableObject;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
public class Brain<E extends LivingEntity> {
private static final Logger LOGGER = LogUtils.getLogger();
private final Supplier<Codec<Brain<E>>> codec;
private static final int SCHEDULE_UPDATE_DELAY = 20;
private final Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = Maps.newHashMap();
private final Map<SensorType<? extends Sensor<? super E>>, Sensor<? super E>> sensors = Maps.newLinkedHashMap();
private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap();
private @Nullable EnvironmentAttribute<Activity> schedule;
private final Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements = Maps.newHashMap();
private final Map<Activity, Set<MemoryModuleType<?>>> activityMemoriesToEraseWhenStopped = Maps.newHashMap();
private Set<Activity> coreActivities = Sets.newHashSet();
private final Set<Activity> activeActivities = Sets.newHashSet();
private Activity defaultActivity = Activity.IDLE;
private long lastScheduleUpdate = -9999L;
public static <E extends LivingEntity> Provider<E> provider(Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes) {
return new Provider(memoryTypes, sensorTypes);
}
public static <E extends LivingEntity> Codec<Brain<E>> codec(final Collection<? extends MemoryModuleType<?>> memoryTypes, final Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes) {
final MutableObject codecReference = new MutableObject();
codecReference.setValue((Object)new MapCodec<Brain<E>>(){
public <T> Stream<T> keys(DynamicOps<T> ops) {
return memoryTypes.stream().flatMap(t -> t.getCodec().map(c -> BuiltInRegistries.MEMORY_MODULE_TYPE.getKey((MemoryModuleType<?>)t)).stream()).map(l -> ops.createString(l.toString()));
}
public <T> DataResult<Brain<E>> decode(DynamicOps<T> ops, MapLike<T> input) {
MutableObject result = new MutableObject((Object)DataResult.success((Object)ImmutableList.builder()));
input.entries().forEach(pair -> {
DataResult typeResult = BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().parse(ops, pair.getFirst());
DataResult entryResult = typeResult.flatMap(type -> this.captureRead((MemoryModuleType)type, ops, (Object)pair.getSecond()));
result.setValue((Object)((DataResult)result.get()).apply2(ImmutableList.Builder::add, entryResult));
});
ImmutableList memories = ((DataResult)result.get()).resultOrPartial(arg_0 -> ((Logger)LOGGER).error(arg_0)).map(ImmutableList.Builder::build).orElseGet(ImmutableList::of);
return DataResult.success(new Brain(memoryTypes, sensorTypes, (ImmutableList<MemoryValue<?>>)memories, codecReference));
}
private <T, U> DataResult<MemoryValue<U>> captureRead(MemoryModuleType<U> type, DynamicOps<T> ops, T input) {
return type.getCodec().map(DataResult::success).orElseGet(() -> DataResult.error(() -> "No codec for memory: " + String.valueOf(type))).flatMap(c -> c.parse(ops, input)).map(v -> new MemoryValue(type, Optional.of(v)));
}
public <T> RecordBuilder<T> encode(Brain<E> input, DynamicOps<T> ops, RecordBuilder<T> prefix) {
input.memories().forEach(m -> m.serialize(ops, prefix));
return prefix;
}
}.fieldOf("memories").codec());
return (Codec)codecReference.get();
}
public Brain(Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes, ImmutableList<MemoryValue<?>> memories, Supplier<Codec<Brain<E>>> codec) {
this.codec = codec;
for (MemoryModuleType<?> memoryModuleType : memoryTypes) {
this.memories.put(memoryModuleType, Optional.empty());
}
for (SensorType sensorType : sensorTypes) {
this.sensors.put(sensorType, (Sensor<E>)sensorType.create());
}
for (Sensor sensor : this.sensors.values()) {
for (MemoryModuleType<?> type : sensor.requires()) {
this.memories.put(type, Optional.empty());
}
}
for (MemoryValue memoryValue : memories) {
memoryValue.setMemoryInternal(this);
}
}
public <T> DataResult<T> serializeStart(DynamicOps<T> ops) {
return this.codec.get().encodeStart(ops, (Object)this);
}
private Stream<MemoryValue<?>> memories() {
return this.memories.entrySet().stream().map(e -> MemoryValue.createUnchecked((MemoryModuleType)e.getKey(), (Optional)e.getValue()));
}
public boolean hasMemoryValue(MemoryModuleType<?> type) {
return this.checkMemory(type, MemoryStatus.VALUE_PRESENT);
}
public void clearMemories() {
this.memories.keySet().forEach(key -> this.memories.put((MemoryModuleType<?>)key, Optional.empty()));
}
public <U> void eraseMemory(MemoryModuleType<U> type) {
this.setMemory(type, Optional.empty());
}
public <U> void setMemory(MemoryModuleType<U> type, @Nullable U value) {
this.setMemory(type, Optional.ofNullable(value));
}
public <U> void setMemoryWithExpiry(MemoryModuleType<U> type, U value, long timeToLive) {
this.setMemoryInternal(type, Optional.of(ExpirableValue.of(value, timeToLive)));
}
public <U> void setMemory(MemoryModuleType<U> type, Optional<? extends U> optionalValue) {
this.setMemoryInternal(type, optionalValue.map(ExpirableValue::of));
}
private <U> void setMemoryInternal(MemoryModuleType<U> type, Optional<? extends ExpirableValue<?>> optionalExpirableValue) {
if (this.memories.containsKey(type)) {
if (optionalExpirableValue.isPresent() && this.isEmptyCollection(optionalExpirableValue.get().getValue())) {
this.eraseMemory(type);
} else {
this.memories.put(type, optionalExpirableValue);
}
}
}
public <U> Optional<U> getMemory(MemoryModuleType<U> type) {
Optional<ExpirableValue<?>> expirableValue = this.memories.get(type);
if (expirableValue == null) {
throw new IllegalStateException("Unregistered memory fetched: " + String.valueOf(type));
}
return expirableValue.map(ExpirableValue::getValue);
}
public <U> @Nullable Optional<U> getMemoryInternal(MemoryModuleType<U> type) {
Optional<ExpirableValue<?>> expirableValue = this.memories.get(type);
if (expirableValue == null) {
return null;
}
return expirableValue.map(ExpirableValue::getValue);
}
public <U> long getTimeUntilExpiry(MemoryModuleType<U> type) {
Optional<ExpirableValue<?>> memory = this.memories.get(type);
return memory.map(ExpirableValue::getTimeToLive).orElse(0L);
}
@Deprecated
@VisibleForDebug
public Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> getMemories() {
return this.memories;
}
public <U> boolean isMemoryValue(MemoryModuleType<U> memoryType, U value) {
if (!this.hasMemoryValue(memoryType)) {
return false;
}
return this.getMemory(memoryType).filter(memory -> memory.equals(value)).isPresent();
}
public boolean checkMemory(MemoryModuleType<?> type, MemoryStatus status) {
Optional<ExpirableValue<?>> optionalExpirableValue = this.memories.get(type);
if (optionalExpirableValue == null) {
return false;
}
return status == MemoryStatus.REGISTERED || status == MemoryStatus.VALUE_PRESENT && optionalExpirableValue.isPresent() || status == MemoryStatus.VALUE_ABSENT && optionalExpirableValue.isEmpty();
}
public void setSchedule(EnvironmentAttribute<Activity> schedule) {
this.schedule = schedule;
}
public void setCoreActivities(Set<Activity> activities) {
this.coreActivities = activities;
}
@Deprecated
@VisibleForDebug
public Set<Activity> getActiveActivities() {
return this.activeActivities;
}
@Deprecated
@VisibleForDebug
public List<BehaviorControl<? super E>> getRunningBehaviors() {
ObjectArrayList runningBehaviours = new ObjectArrayList();
for (Map<Activity, Set<BehaviorControl<E>>> behavioursByActivities : this.availableBehaviorsByPriority.values()) {
for (Set<BehaviorControl<E>> behaviors : behavioursByActivities.values()) {
for (BehaviorControl<E> behavior : behaviors) {
if (behavior.getStatus() != Behavior.Status.RUNNING) continue;
runningBehaviours.add(behavior);
}
}
}
return runningBehaviours;
}
public void useDefaultActivity() {
this.setActiveActivity(this.defaultActivity);
}
public Optional<Activity> getActiveNonCoreActivity() {
for (Activity activity : this.activeActivities) {
if (this.coreActivities.contains(activity)) continue;
return Optional.of(activity);
}
return Optional.empty();
}
public void setActiveActivityIfPossible(Activity activity) {
if (this.activityRequirementsAreMet(activity)) {
this.setActiveActivity(activity);
} else {
this.useDefaultActivity();
}
}
private void setActiveActivity(Activity activity) {
if (this.isActive(activity)) {
return;
}
this.eraseMemoriesForOtherActivitesThan(activity);
this.activeActivities.clear();
this.activeActivities.addAll(this.coreActivities);
this.activeActivities.add(activity);
}
private void eraseMemoriesForOtherActivitesThan(Activity activity) {
for (Activity oldActivity : this.activeActivities) {
Set<MemoryModuleType<?>> memoryModuleTypes;
if (oldActivity == activity || (memoryModuleTypes = this.activityMemoriesToEraseWhenStopped.get(oldActivity)) == null) continue;
for (MemoryModuleType<?> memoryModuleType : memoryModuleTypes) {
this.eraseMemory(memoryModuleType);
}
}
}
public void updateActivityFromSchedule(EnvironmentAttributeSystem environmentAttributes, long gameTime, Vec3 pos) {
if (gameTime - this.lastScheduleUpdate > 20L) {
Activity scheduledActivity;
this.lastScheduleUpdate = gameTime;
Activity activity = scheduledActivity = this.schedule != null ? environmentAttributes.getValue(this.schedule, pos) : Activity.IDLE;
if (!this.activeActivities.contains(scheduledActivity)) {
this.setActiveActivityIfPossible(scheduledActivity);
}
}
}
public void setActiveActivityToFirstValid(List<Activity> activities) {
for (Activity activity : activities) {
if (!this.activityRequirementsAreMet(activity)) continue;
this.setActiveActivity(activity);
break;
}
}
public void setDefaultActivity(Activity activity) {
this.defaultActivity = activity;
}
public void addActivity(Activity activity, int priorityOfFirstBehavior, ImmutableList<? extends BehaviorControl<? super E>> behaviorList) {
this.addActivity(activity, this.createPriorityPairs(priorityOfFirstBehavior, behaviorList));
}
public void addActivityAndRemoveMemoryWhenStopped(Activity activity, int priorityOfFirstBehavior, ImmutableList<? extends BehaviorControl<? super E>> behaviorList, MemoryModuleType<?> memoryThatMustHaveValueAndWillBeErasedAfter) {
ImmutableSet conditions = ImmutableSet.of((Object)Pair.of(memoryThatMustHaveValueAndWillBeErasedAfter, (Object)((Object)MemoryStatus.VALUE_PRESENT)));
ImmutableSet memoriesToEraseWhenStopped = ImmutableSet.of(memoryThatMustHaveValueAndWillBeErasedAfter);
this.addActivityAndRemoveMemoriesWhenStopped(activity, (ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>>)this.createPriorityPairs(priorityOfFirstBehavior, behaviorList), (Set<Pair<MemoryModuleType<?>, MemoryStatus>>)conditions, (Set<MemoryModuleType<?>>)memoriesToEraseWhenStopped);
}
public void addActivity(Activity activity, ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> behaviorPriorityPairs) {
this.addActivityAndRemoveMemoriesWhenStopped(activity, behaviorPriorityPairs, (Set<Pair<MemoryModuleType<?>, MemoryStatus>>)ImmutableSet.of(), Sets.newHashSet());
}
public void addActivityWithConditions(Activity activity, int priorityOfFirstBehavior, ImmutableList<? extends BehaviorControl<? super E>> behaviorList, Set<Pair<MemoryModuleType<?>, MemoryStatus>> conditions) {
this.addActivityWithConditions(activity, this.createPriorityPairs(priorityOfFirstBehavior, behaviorList), conditions);
}
public void addActivityWithConditions(Activity activity, ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> behaviorPriorityPairs, Set<Pair<MemoryModuleType<?>, MemoryStatus>> conditions) {
this.addActivityAndRemoveMemoriesWhenStopped(activity, behaviorPriorityPairs, conditions, Sets.newHashSet());
}
public void addActivityAndRemoveMemoriesWhenStopped(Activity activity, ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> behaviorPriorityPairs, Set<Pair<MemoryModuleType<?>, MemoryStatus>> conditions, Set<MemoryModuleType<?>> memoriesToEraseWhenStopped) {
this.activityRequirements.put(activity, conditions);
if (!memoriesToEraseWhenStopped.isEmpty()) {
this.activityMemoriesToEraseWhenStopped.put(activity, memoriesToEraseWhenStopped);
}
for (Pair pair : behaviorPriorityPairs) {
this.availableBehaviorsByPriority.computeIfAbsent((Integer)pair.getFirst(), key -> Maps.newHashMap()).computeIfAbsent(activity, key -> Sets.newLinkedHashSet()).add((BehaviorControl)pair.getSecond());
}
}
@VisibleForTesting
public void removeAllBehaviors() {
this.availableBehaviorsByPriority.clear();
}
public boolean isActive(Activity activity) {
return this.activeActivities.contains(activity);
}
public Brain<E> copyWithoutBehaviors() {
Brain<E> brain = new Brain<E>(this.memories.keySet(), this.sensors.keySet(), ImmutableList.of(), this.codec);
for (Map.Entry<MemoryModuleType<?>, Optional<ExpirableValue<?>>> memoryEntry : this.memories.entrySet()) {
MemoryModuleType<?> memoryModuleType = memoryEntry.getKey();
if (!memoryEntry.getValue().isPresent()) continue;
brain.memories.put(memoryModuleType, memoryEntry.getValue());
}
return brain;
}
public void tick(ServerLevel level, E body) {
this.forgetOutdatedMemories();
this.tickSensors(level, body);
this.startEachNonRunningBehavior(level, body);
this.tickEachRunningBehavior(level, body);
}
private void tickSensors(ServerLevel level, E body) {
for (Sensor<E> sensor : this.sensors.values()) {
sensor.tick(level, body);
}
}
private void forgetOutdatedMemories() {
for (Map.Entry<MemoryModuleType<?>, Optional<ExpirableValue<?>>> entry : this.memories.entrySet()) {
if (!entry.getValue().isPresent()) continue;
ExpirableValue<?> memory = entry.getValue().get();
if (memory.hasExpired()) {
this.eraseMemory(entry.getKey());
}
memory.tick();
}
}
public void stopAll(ServerLevel level, E body) {
long timestamp = ((Entity)body).level().getGameTime();
for (BehaviorControl<E> behavior : this.getRunningBehaviors()) {
behavior.doStop(level, body, timestamp);
}
}
private void startEachNonRunningBehavior(ServerLevel level, E body) {
long time = level.getGameTime();
for (Map<Activity, Set<BehaviorControl<E>>> behavioursByActivities : this.availableBehaviorsByPriority.values()) {
for (Map.Entry<Activity, Set<BehaviorControl<E>>> behavioursForActivity : behavioursByActivities.entrySet()) {
Activity activity = behavioursForActivity.getKey();
if (!this.activeActivities.contains(activity)) continue;
Set<BehaviorControl<E>> behaviors = behavioursForActivity.getValue();
for (BehaviorControl<E> behavior : behaviors) {
if (behavior.getStatus() != Behavior.Status.STOPPED) continue;
behavior.tryStart(level, body, time);
}
}
}
}
private void tickEachRunningBehavior(ServerLevel level, E body) {
long timestamp = level.getGameTime();
for (BehaviorControl<E> behavior : this.getRunningBehaviors()) {
behavior.tickOrStop(level, body, timestamp);
}
}
private boolean activityRequirementsAreMet(Activity activity) {
if (!this.activityRequirements.containsKey(activity)) {
return false;
}
for (Pair<MemoryModuleType<?>, MemoryStatus> memoryRequirement : this.activityRequirements.get(activity)) {
MemoryStatus memoryStatus;
MemoryModuleType memoryType = (MemoryModuleType)memoryRequirement.getFirst();
if (this.checkMemory(memoryType, memoryStatus = (MemoryStatus)((Object)memoryRequirement.getSecond()))) continue;
return false;
}
return true;
}
private boolean isEmptyCollection(Object object) {
return object instanceof Collection && ((Collection)object).isEmpty();
}
ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> createPriorityPairs(int priorityOfFirstBehavior, ImmutableList<? extends BehaviorControl<? super E>> behaviorList) {
int nextPrio = priorityOfFirstBehavior;
ImmutableList.Builder listBuilder = ImmutableList.builder();
for (BehaviorControl behavior : behaviorList) {
listBuilder.add((Object)Pair.of((Object)nextPrio++, (Object)behavior));
}
return listBuilder.build();
}
public boolean isBrainDead() {
return this.memories.isEmpty() && this.sensors.isEmpty() && this.availableBehaviorsByPriority.isEmpty();
}
public static final class Provider<E extends LivingEntity> {
private final Collection<? extends MemoryModuleType<?>> memoryTypes;
private final Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes;
private final Codec<Brain<E>> codec;
private Provider(Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes) {
this.memoryTypes = memoryTypes;
this.sensorTypes = sensorTypes;
this.codec = Brain.codec(memoryTypes, sensorTypes);
}
public Brain<E> makeBrain(Dynamic<?> input) {
return this.codec.parse(input).resultOrPartial(arg_0 -> ((Logger)LOGGER).error(arg_0)).orElseGet(() -> new Brain(this.memoryTypes, this.sensorTypes, ImmutableList.of(), () -> this.codec));
}
}
private static final class MemoryValue<U> {
private final MemoryModuleType<U> type;
private final Optional<? extends ExpirableValue<U>> value;
private static <U> MemoryValue<U> createUnchecked(MemoryModuleType<U> type, Optional<? extends ExpirableValue<?>> value) {
return new MemoryValue<U>(type, value);
}
private MemoryValue(MemoryModuleType<U> type, Optional<? extends ExpirableValue<U>> value) {
this.type = type;
this.value = value;
}
private void setMemoryInternal(Brain<?> brain) {
brain.setMemoryInternal(this.type, this.value);
}
public <T> void serialize(DynamicOps<T> ops, RecordBuilder<T> builder) {
this.type.getCodec().ifPresent(codec -> this.value.ifPresent(v -> builder.add(BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().encodeStart(ops, this.type), codec.encodeStart(ops, v))));
}
}
}