540 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			540 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| 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.google.common.collect.ImmutableList.Builder;
 | |
| 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.Map.Entry;
 | |
| 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.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.entity.schedule.Schedule;
 | |
| import org.apache.commons.lang3.mutable.MutableObject;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| public class Brain<E extends LivingEntity> {
 | |
| 	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.<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>>newHashMap();
 | |
| 	private final Map<SensorType<? extends Sensor<? super E>>, Sensor<? super E>> sensors = Maps.<SensorType<? extends Sensor<? super E>>, Sensor<? super E>>newLinkedHashMap();
 | |
| 	private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap();
 | |
| 	private Schedule schedule = Schedule.EMPTY;
 | |
| 	private final Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements = Maps.<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>>newHashMap();
 | |
| 	private final Map<Activity, Set<MemoryModuleType<?>>> activityMemoriesToEraseWhenStopped = Maps.<Activity, Set<MemoryModuleType<?>>>newHashMap();
 | |
| 	private Set<Activity> coreActivities = Sets.<Activity>newHashSet();
 | |
| 	private final Set<Activity> activeActivities = Sets.<Activity>newHashSet();
 | |
| 	private Activity defaultActivity = Activity.IDLE;
 | |
| 	private long lastScheduleUpdate = -9999L;
 | |
| 
 | |
| 	public static <E extends LivingEntity> Brain.Provider<E> provider(
 | |
| 		Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes
 | |
| 	) {
 | |
| 		return new Brain.Provider<>(memoryTypes, sensorTypes);
 | |
| 	}
 | |
| 
 | |
| 	public static <E extends LivingEntity> Codec<Brain<E>> codec(
 | |
| 		Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes
 | |
| 	) {
 | |
| 		final MutableObject<Codec<Brain<E>>> mutableObject = new MutableObject<>();
 | |
| 		mutableObject.setValue(
 | |
| 			(new MapCodec<Brain<E>>() {
 | |
| 					@Override
 | |
| 					public <T> Stream<T> keys(DynamicOps<T> dynamicOps) {
 | |
| 						return memoryTypes.stream()
 | |
| 							.flatMap(memoryModuleType -> memoryModuleType.getCodec().map(codec -> BuiltInRegistries.MEMORY_MODULE_TYPE.getKey(memoryModuleType)).stream())
 | |
| 							.map(resourceLocation -> dynamicOps.createString(resourceLocation.toString()));
 | |
| 					}
 | |
| 
 | |
| 					@Override
 | |
| 					public <T> DataResult<Brain<E>> decode(DynamicOps<T> dynamicOps, MapLike<T> mapLike) {
 | |
| 						MutableObject<DataResult<Builder<Brain.MemoryValue<?>>>> mutableObjectx = new MutableObject<>(DataResult.success(ImmutableList.builder()));
 | |
| 						mapLike.entries()
 | |
| 							.forEach(
 | |
| 								pair -> {
 | |
| 									DataResult<MemoryModuleType<?>> dataResult = BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().parse(dynamicOps, (T)pair.getFirst());
 | |
| 									DataResult<? extends Brain.MemoryValue<?>> dataResult2 = dataResult.flatMap(
 | |
| 										memoryModuleType -> this.captureRead(memoryModuleType, dynamicOps, (T)pair.getSecond())
 | |
| 									);
 | |
| 									mutableObject.setValue(mutableObject.getValue().apply2(Builder::add, dataResult2));
 | |
| 								}
 | |
| 							);
 | |
| 						ImmutableList<Brain.MemoryValue<?>> immutableList = (ImmutableList<Brain.MemoryValue<?>>)mutableObjectx.getValue()
 | |
| 							.resultOrPartial(Brain.LOGGER::error)
 | |
| 							.map(Builder::build)
 | |
| 							.orElseGet(ImmutableList::of);
 | |
| 						return DataResult.success(new Brain<>(memoryTypes, sensorTypes, immutableList, mutableObject::getValue));
 | |
| 					}
 | |
| 
 | |
| 					private <T, U> DataResult<Brain.MemoryValue<U>> captureRead(MemoryModuleType<U> memoryModuleType, DynamicOps<T> dynamicOps, T object) {
 | |
| 						return ((DataResult)memoryModuleType.getCodec()
 | |
| 								.map(DataResult::success)
 | |
| 								.orElseGet(() -> DataResult.error(() -> "No codec for memory: " + memoryModuleType)))
 | |
| 							.flatMap(codec -> codec.parse(dynamicOps, object))
 | |
| 							.map(expirableValue -> new Brain.MemoryValue<>(memoryModuleType, Optional.of(expirableValue)));
 | |
| 					}
 | |
| 
 | |
| 					public <T> RecordBuilder<T> encode(Brain<E> input, DynamicOps<T> ops, RecordBuilder<T> prefix) {
 | |
| 						input.memories().forEach(memoryValue -> memoryValue.serialize(ops, prefix));
 | |
| 						return prefix;
 | |
| 					}
 | |
| 				})
 | |
| 				.fieldOf("memories")
 | |
| 				.codec()
 | |
| 		);
 | |
| 		return mutableObject.getValue();
 | |
| 	}
 | |
| 
 | |
| 	public Brain(
 | |
| 		Collection<? extends MemoryModuleType<?>> memoryModuleTypes,
 | |
| 		Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes,
 | |
| 		ImmutableList<Brain.MemoryValue<?>> memoryValues,
 | |
| 		Supplier<Codec<Brain<E>>> codec
 | |
| 	) {
 | |
| 		this.codec = codec;
 | |
| 
 | |
| 		for (MemoryModuleType<?> memoryModuleType : memoryModuleTypes) {
 | |
| 			this.memories.put(memoryModuleType, Optional.empty());
 | |
| 		}
 | |
| 
 | |
| 		for (SensorType<? extends Sensor<? super E>> sensorType : sensorTypes) {
 | |
| 			this.sensors.put(sensorType, sensorType.create());
 | |
| 		}
 | |
| 
 | |
| 		for (Sensor<? super E> sensor : this.sensors.values()) {
 | |
| 			for (MemoryModuleType<?> memoryModuleType2 : sensor.requires()) {
 | |
| 				this.memories.put(memoryModuleType2, Optional.empty());
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for (Brain.MemoryValue<?> memoryValue : memoryValues) {
 | |
| 			memoryValue.setMemoryInternal(this);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public <T> DataResult<T> serializeStart(DynamicOps<T> ops) {
 | |
| 		return ((Codec)this.codec.get()).encodeStart(ops, this);
 | |
| 	}
 | |
| 
 | |
| 	Stream<Brain.MemoryValue<?>> memories() {
 | |
| 		return this.memories
 | |
| 			.entrySet()
 | |
| 			.stream()
 | |
| 			.map(entry -> Brain.MemoryValue.createUnchecked((MemoryModuleType)entry.getKey(), (Optional<? extends ExpirableValue<?>>)entry.getValue()));
 | |
| 	}
 | |
| 
 | |
| 	public boolean hasMemoryValue(MemoryModuleType<?> type) {
 | |
| 		return this.checkMemory(type, MemoryStatus.VALUE_PRESENT);
 | |
| 	}
 | |
| 
 | |
| 	public void clearMemories() {
 | |
| 		this.memories.keySet().forEach(memoryModuleType -> this.memories.put(memoryModuleType, Optional.empty()));
 | |
| 	}
 | |
| 
 | |
| 	public <U> void eraseMemory(MemoryModuleType<U> type) {
 | |
| 		this.setMemory(type, Optional.empty());
 | |
| 	}
 | |
| 
 | |
| 	public <U> void setMemory(MemoryModuleType<U> memoryType, @Nullable U memory) {
 | |
| 		this.setMemory(memoryType, Optional.ofNullable(memory));
 | |
| 	}
 | |
| 
 | |
| 	public <U> void setMemoryWithExpiry(MemoryModuleType<U> memoryType, U memory, long timeToLive) {
 | |
| 		this.setMemoryInternal(memoryType, Optional.of(ExpirableValue.of(memory, timeToLive)));
 | |
| 	}
 | |
| 
 | |
| 	public <U> void setMemory(MemoryModuleType<U> memoryType, Optional<? extends U> memory) {
 | |
| 		this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of));
 | |
| 	}
 | |
| 
 | |
| 	<U> void setMemoryInternal(MemoryModuleType<U> memoryType, Optional<? extends ExpirableValue<?>> memory) {
 | |
| 		if (this.memories.containsKey(memoryType)) {
 | |
| 			if (memory.isPresent() && this.isEmptyCollection(((ExpirableValue)memory.get()).getValue())) {
 | |
| 				this.eraseMemory(memoryType);
 | |
| 			} else {
 | |
| 				this.memories.put(memoryType, memory);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public <U> Optional<U> getMemory(MemoryModuleType<U> type) {
 | |
| 		Optional<? extends ExpirableValue<?>> optional = (Optional<? extends ExpirableValue<?>>)this.memories.get(type);
 | |
| 		if (optional == null) {
 | |
| 			throw new IllegalStateException("Unregistered memory fetched: " + type);
 | |
| 		} else {
 | |
| 			return optional.map(ExpirableValue::getValue);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public <U> Optional<U> getMemoryInternal(MemoryModuleType<U> type) {
 | |
| 		Optional<? extends ExpirableValue<?>> optional = (Optional<? extends ExpirableValue<?>>)this.memories.get(type);
 | |
| 		return optional == null ? null : optional.map(ExpirableValue::getValue);
 | |
| 	}
 | |
| 
 | |
| 	public <U> long getTimeUntilExpiry(MemoryModuleType<U> memoryType) {
 | |
| 		Optional<? extends ExpirableValue<?>> optional = (Optional<? extends ExpirableValue<?>>)this.memories.get(memoryType);
 | |
| 		return (Long)optional.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 memory) {
 | |
| 		return !this.hasMemoryValue(memoryType) ? false : this.getMemory(memoryType).filter(object2 -> object2.equals(memory)).isPresent();
 | |
| 	}
 | |
| 
 | |
| 	public boolean checkMemory(MemoryModuleType<?> memoryType, MemoryStatus memoryStatus) {
 | |
| 		Optional<? extends ExpirableValue<?>> optional = (Optional<? extends ExpirableValue<?>>)this.memories.get(memoryType);
 | |
| 		return optional == null
 | |
| 			? false
 | |
| 			: memoryStatus == MemoryStatus.REGISTERED
 | |
| 				|| memoryStatus == MemoryStatus.VALUE_PRESENT && optional.isPresent()
 | |
| 				|| memoryStatus == MemoryStatus.VALUE_ABSENT && optional.isEmpty();
 | |
| 	}
 | |
| 
 | |
| 	public Schedule getSchedule() {
 | |
| 		return this.schedule;
 | |
| 	}
 | |
| 
 | |
| 	public void setSchedule(Schedule newSchedule) {
 | |
| 		this.schedule = newSchedule;
 | |
| 	}
 | |
| 
 | |
| 	public void setCoreActivities(Set<Activity> newActivities) {
 | |
| 		this.coreActivities = newActivities;
 | |
| 	}
 | |
| 
 | |
| 	@Deprecated
 | |
| 	@VisibleForDebug
 | |
| 	public Set<Activity> getActiveActivities() {
 | |
| 		return this.activeActivities;
 | |
| 	}
 | |
| 
 | |
| 	@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;
 | |
| 	}
 | |
| 
 | |
| 	public void useDefaultActivity() {
 | |
| 		this.setActiveActivity(this.defaultActivity);
 | |
| 	}
 | |
| 
 | |
| 	public Optional<Activity> getActiveNonCoreActivity() {
 | |
| 		for (Activity activity : this.activeActivities) {
 | |
| 			if (!this.coreActivities.contains(activity)) {
 | |
| 				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)) {
 | |
| 			this.eraseMemoriesForOtherActivitesThan(activity);
 | |
| 			this.activeActivities.clear();
 | |
| 			this.activeActivities.addAll(this.coreActivities);
 | |
| 			this.activeActivities.add(activity);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void eraseMemoriesForOtherActivitesThan(Activity activity) {
 | |
| 		for (Activity activity2 : this.activeActivities) {
 | |
| 			if (activity2 != activity) {
 | |
| 				Set<MemoryModuleType<?>> set = (Set<MemoryModuleType<?>>)this.activityMemoriesToEraseWhenStopped.get(activity2);
 | |
| 				if (set != null) {
 | |
| 					for (MemoryModuleType<?> memoryModuleType : set) {
 | |
| 						this.eraseMemory(memoryModuleType);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void updateActivityFromSchedule(long dayTime, long gameTime) {
 | |
| 		if (gameTime - this.lastScheduleUpdate > 20L) {
 | |
| 			this.lastScheduleUpdate = gameTime;
 | |
| 			Activity activity = this.getSchedule().getActivityAt((int)(dayTime % 24000L));
 | |
| 			if (!this.activeActivities.contains(activity)) {
 | |
| 				this.setActiveActivityIfPossible(activity);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void setActiveActivityToFirstValid(List<Activity> activities) {
 | |
| 		for (Activity activity : activities) {
 | |
| 			if (this.activityRequirementsAreMet(activity)) {
 | |
| 				this.setActiveActivity(activity);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void setDefaultActivity(Activity newFallbackActivity) {
 | |
| 		this.defaultActivity = newFallbackActivity;
 | |
| 	}
 | |
| 
 | |
| 	public void addActivity(Activity activity, int priorityStart, ImmutableList<? extends BehaviorControl<? super E>> tasks) {
 | |
| 		this.addActivity(activity, this.createPriorityPairs(priorityStart, tasks));
 | |
| 	}
 | |
| 
 | |
| 	public void addActivityAndRemoveMemoryWhenStopped(
 | |
| 		Activity activity, int priorityStart, ImmutableList<? extends BehaviorControl<? super E>> tasks, MemoryModuleType<?> memoryType
 | |
| 	) {
 | |
| 		Set<Pair<MemoryModuleType<?>, MemoryStatus>> set = ImmutableSet.of(Pair.of(memoryType, MemoryStatus.VALUE_PRESENT));
 | |
| 		Set<MemoryModuleType<?>> set2 = ImmutableSet.of(memoryType);
 | |
| 		this.addActivityAndRemoveMemoriesWhenStopped(activity, this.createPriorityPairs(priorityStart, tasks), set, set2);
 | |
| 	}
 | |
| 
 | |
| 	public void addActivity(Activity activity, ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> tasks) {
 | |
| 		this.addActivityAndRemoveMemoriesWhenStopped(activity, tasks, ImmutableSet.of(), Sets.<MemoryModuleType<?>>newHashSet());
 | |
| 	}
 | |
| 
 | |
| 	public void addActivityWithConditions(
 | |
| 		Activity activity, int priorityStart, ImmutableList<? extends BehaviorControl<? super E>> tasks, Set<Pair<MemoryModuleType<?>, MemoryStatus>> memoryStatuses
 | |
| 	) {
 | |
| 		this.addActivityWithConditions(activity, this.createPriorityPairs(priorityStart, tasks), memoryStatuses);
 | |
| 	}
 | |
| 
 | |
| 	public void addActivityWithConditions(
 | |
| 		Activity activity,
 | |
| 		ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> tasks,
 | |
| 		Set<Pair<MemoryModuleType<?>, MemoryStatus>> memoryStatuses
 | |
| 	) {
 | |
| 		this.addActivityAndRemoveMemoriesWhenStopped(activity, tasks, memoryStatuses, Sets.<MemoryModuleType<?>>newHashSet());
 | |
| 	}
 | |
| 
 | |
| 	public void addActivityAndRemoveMemoriesWhenStopped(
 | |
| 		Activity activity,
 | |
| 		ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> tasks,
 | |
| 		Set<Pair<MemoryModuleType<?>, MemoryStatus>> memoryStatuses,
 | |
| 		Set<MemoryModuleType<?>> memoryTypes
 | |
| 	) {
 | |
| 		this.activityRequirements.put(activity, memoryStatuses);
 | |
| 		if (!memoryTypes.isEmpty()) {
 | |
| 			this.activityMemoriesToEraseWhenStopped.put(activity, memoryTypes);
 | |
| 		}
 | |
| 
 | |
| 		for (Pair<Integer, ? extends BehaviorControl<? super E>> pair : tasks) {
 | |
| 			((Set)((Map)this.availableBehaviorsByPriority.computeIfAbsent(pair.getFirst(), integer -> Maps.newHashMap()))
 | |
| 					.computeIfAbsent(activity, activityx -> Sets.newLinkedHashSet()))
 | |
| 				.add(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<>(this.memories.keySet(), this.sensors.keySet(), ImmutableList.of(), this.codec);
 | |
| 
 | |
| 		for (Entry<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> entry : this.memories.entrySet()) {
 | |
| 			MemoryModuleType<?> memoryModuleType = (MemoryModuleType<?>)entry.getKey();
 | |
| 			if (((Optional)entry.getValue()).isPresent()) {
 | |
| 				brain.memories.put(memoryModuleType, (Optional)entry.getValue());
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return brain;
 | |
| 	}
 | |
| 
 | |
| 	public void tick(ServerLevel level, E entity) {
 | |
| 		this.forgetOutdatedMemories();
 | |
| 		this.tickSensors(level, entity);
 | |
| 		this.startEachNonRunningBehavior(level, entity);
 | |
| 		this.tickEachRunningBehavior(level, entity);
 | |
| 	}
 | |
| 
 | |
| 	private void tickSensors(ServerLevel level, E brainHolder) {
 | |
| 		for (Sensor<? super E> sensor : this.sensors.values()) {
 | |
| 			sensor.tick(level, brainHolder);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void forgetOutdatedMemories() {
 | |
| 		for (Entry<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> entry : this.memories.entrySet()) {
 | |
| 			if (((Optional)entry.getValue()).isPresent()) {
 | |
| 				ExpirableValue<?> expirableValue = (ExpirableValue<?>)((Optional)entry.getValue()).get();
 | |
| 				if (expirableValue.hasExpired()) {
 | |
| 					this.eraseMemory((MemoryModuleType)entry.getKey());
 | |
| 				}
 | |
| 
 | |
| 				expirableValue.tick();
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void stopAll(ServerLevel level, E owner) {
 | |
| 		long l = owner.level().getGameTime();
 | |
| 
 | |
| 		for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
 | |
| 			behaviorControl.doStop(level, owner, l);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void startEachNonRunningBehavior(ServerLevel level, E entity) {
 | |
| 		long l = level.getGameTime();
 | |
| 
 | |
| 		for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
 | |
| 			for (Entry<Activity, Set<BehaviorControl<? super E>>> entry : map.entrySet()) {
 | |
| 				Activity activity = (Activity)entry.getKey();
 | |
| 				if (this.activeActivities.contains(activity)) {
 | |
| 					for (BehaviorControl<? super E> behaviorControl : (Set)entry.getValue()) {
 | |
| 						if (behaviorControl.getStatus() == Behavior.Status.STOPPED) {
 | |
| 							behaviorControl.tryStart(level, entity, l);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void tickEachRunningBehavior(ServerLevel level, E entity) {
 | |
| 		long l = level.getGameTime();
 | |
| 
 | |
| 		for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
 | |
| 			behaviorControl.tickOrStop(level, entity, l);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean activityRequirementsAreMet(Activity activity) {
 | |
| 		if (!this.activityRequirements.containsKey(activity)) {
 | |
| 			return false;
 | |
| 		} else {
 | |
| 			for (Pair<MemoryModuleType<?>, MemoryStatus> pair : (Set)this.activityRequirements.get(activity)) {
 | |
| 				MemoryModuleType<?> memoryModuleType = pair.getFirst();
 | |
| 				MemoryStatus memoryStatus = pair.getSecond();
 | |
| 				if (!this.checkMemory(memoryModuleType, memoryStatus)) {
 | |
| 					return false;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean isEmptyCollection(Object collection) {
 | |
| 		return collection instanceof Collection && ((Collection)collection).isEmpty();
 | |
| 	}
 | |
| 
 | |
| 	ImmutableList<? extends Pair<Integer, ? extends BehaviorControl<? super E>>> createPriorityPairs(
 | |
| 		int priorityStart, ImmutableList<? extends BehaviorControl<? super E>> tasks
 | |
| 	) {
 | |
| 		int i = priorityStart;
 | |
| 		Builder<Pair<Integer, ? extends BehaviorControl<? super E>>> builder = ImmutableList.builder();
 | |
| 
 | |
| 		for (BehaviorControl<? super E> behaviorControl : tasks) {
 | |
| 			builder.add(Pair.of(i++, behaviorControl));
 | |
| 		}
 | |
| 
 | |
| 		return builder.build();
 | |
| 	}
 | |
| 
 | |
| 	static final class MemoryValue<U> {
 | |
| 		private final MemoryModuleType<U> type;
 | |
| 		private final Optional<? extends ExpirableValue<U>> value;
 | |
| 
 | |
| 		static <U> Brain.MemoryValue<U> createUnchecked(MemoryModuleType<U> memoryType, Optional<? extends ExpirableValue<?>> memory) {
 | |
| 			return new Brain.MemoryValue<>(memoryType, (Optional<? extends ExpirableValue<U>>)memory);
 | |
| 		}
 | |
| 
 | |
| 		MemoryValue(MemoryModuleType<U> type, Optional<? extends ExpirableValue<U>> value) {
 | |
| 			this.type = type;
 | |
| 			this.value = value;
 | |
| 		}
 | |
| 
 | |
| 		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(
 | |
| 							expirableValue -> builder.add(BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().encodeStart(ops, this.type), codec.encodeStart(ops, expirableValue))
 | |
| 						)
 | |
| 				);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	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;
 | |
| 
 | |
| 		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<?> ops) {
 | |
| 			return (Brain<E>)this.codec
 | |
| 				.parse(ops)
 | |
| 				.resultOrPartial(Brain.LOGGER::error)
 | |
| 				.orElseGet(() -> new Brain(this.memoryTypes, this.sensorTypes, ImmutableList.of(), () -> this.codec));
 | |
| 		}
 | |
| 	}
 | |
| }
 |