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 javax.annotation.Nullable; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; 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.slf4j.Logger; 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(); private final Map>, Sensor> sensors = Maps.newLinkedHashMap(); private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); private Schedule schedule = Schedule.EMPTY; private final Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); 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; public static Brain.Provider provider( Collection> p_21924_, Collection>> p_21925_ ) { return new Brain.Provider<>(p_21924_, p_21925_); } public static Codec> codec( final Collection> p_21947_, final Collection>> p_21948_ ) { final MutableObject>> mutableobject = new MutableObject<>(); mutableobject.setValue( (new MapCodec>() { @Override public Stream keys(DynamicOps p_22029_) { return p_21947_.stream() .flatMap( p_22020_ -> p_22020_.getCodec().map(p_258254_ -> BuiltInRegistries.MEMORY_MODULE_TYPE.getKey((MemoryModuleType)p_22020_)).stream() ) .map(p_22018_ -> p_22029_.createString(p_22018_.toString())); } @Override public DataResult> decode(DynamicOps p_22022_, MapLike p_22023_) { MutableObject>>> mutableobject1 = new MutableObject<>( DataResult.success(ImmutableList.builder()) ); p_22023_.entries() .forEach( p_358908_ -> { DataResult> dataresult = BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().parse(p_22022_, p_358908_.getFirst()); DataResult> dataresult1 = dataresult.flatMap( p_147350_ -> this.captureRead((MemoryModuleType)p_147350_, p_22022_, (T)p_358908_.getSecond()) ); mutableobject1.setValue(mutableobject1.getValue().apply2(Builder::add, dataresult1)); } ); ImmutableList> immutablelist = mutableobject1.getValue() .resultOrPartial(Brain.LOGGER::error) .map(Builder::build) .orElseGet(ImmutableList::of); return DataResult.success(new Brain<>(p_21947_, p_21948_, immutablelist, mutableobject::getValue)); } private DataResult> captureRead(MemoryModuleType p_21997_, DynamicOps p_21998_, T p_21999_) { return p_21997_.getCodec() .map(DataResult::success) .orElseGet(() -> DataResult.error(() -> "No codec for memory: " + p_21997_)) .>flatMap(p_22011_ -> p_22011_.parse(p_21998_, p_21999_)) .map(p_21992_ -> new Brain.MemoryValue<>(p_21997_, Optional.of(p_21992_))); } public RecordBuilder encode(Brain p_21985_, DynamicOps p_21986_, RecordBuilder p_21987_) { p_21985_.memories().forEach(p_22007_ -> p_22007_.serialize(p_21986_, p_21987_)); return p_21987_; } }) .fieldOf("memories") .codec() ); return mutableobject.getValue(); } public Brain( Collection> p_21855_, Collection>> p_21856_, ImmutableList> p_21857_, Supplier>> p_21858_ ) { this.codec = p_21858_; for (MemoryModuleType memorymoduletype : p_21855_) { this.memories.put(memorymoduletype, Optional.empty()); } for (SensorType> sensortype : p_21856_) { this.sensors.put(sensortype, (Sensor)sensortype.create()); } for (Sensor sensor : this.sensors.values()) { for (MemoryModuleType memorymoduletype1 : sensor.requires()) { this.memories.put(memorymoduletype1, Optional.empty()); } } for (Brain.MemoryValue memoryvalue : p_21857_) { memoryvalue.setMemoryInternal(this); } } public DataResult serializeStart(DynamicOps p_21915_) { return this.codec.get().encodeStart(p_21915_, this); } Stream> memories() { return this.memories.entrySet().stream().map(p_21929_ -> Brain.MemoryValue.createUnchecked(p_21929_.getKey(), p_21929_.getValue())); } public boolean hasMemoryValue(MemoryModuleType p_21875_) { return this.checkMemory(p_21875_, MemoryStatus.VALUE_PRESENT); } public void clearMemories() { this.memories.keySet().forEach(p_276103_ -> this.memories.put((MemoryModuleType)p_276103_, Optional.empty())); } public void eraseMemory(MemoryModuleType p_21937_) { this.setMemory(p_21937_, Optional.empty()); } public void setMemory(MemoryModuleType p_21880_, @Nullable U p_21881_) { this.setMemory(p_21880_, Optional.ofNullable(p_21881_)); } public void setMemoryWithExpiry(MemoryModuleType p_21883_, U p_21884_, long p_21885_) { this.setMemoryInternal(p_21883_, Optional.of(ExpirableValue.of(p_21884_, p_21885_))); } public void setMemory(MemoryModuleType p_21887_, Optional p_21888_) { this.setMemoryInternal(p_21887_, p_21888_.map(ExpirableValue::of)); } void setMemoryInternal(MemoryModuleType p_21942_, Optional> p_21943_) { if (this.memories.containsKey(p_21942_)) { if (p_21943_.isPresent() && this.isEmptyCollection(p_21943_.get().getValue())) { this.eraseMemory(p_21942_); } else { this.memories.put(p_21942_, p_21943_); } } } public Optional getMemory(MemoryModuleType p_21953_) { Optional> optional = this.memories.get(p_21953_); if (optional == null) { throw new IllegalStateException("Unregistered memory fetched: " + p_21953_); } else { return (Optional)optional.map(ExpirableValue::getValue); } } @Nullable public Optional getMemoryInternal(MemoryModuleType p_259344_) { Optional> optional = this.memories.get(p_259344_); return optional == null ? null : (Optional)optional.map(ExpirableValue::getValue); } public long getTimeUntilExpiry(MemoryModuleType p_147342_) { Optional> optional = this.memories.get(p_147342_); return optional.map(ExpirableValue::getTimeToLive).orElse(0L); } @Deprecated @VisibleForDebug public Map, Optional>> getMemories() { return this.memories; } public boolean isMemoryValue(MemoryModuleType p_21939_, U p_21940_) { return !this.hasMemoryValue(p_21939_) ? false : this.getMemory(p_21939_).filter(p_21922_ -> p_21922_.equals(p_21940_)).isPresent(); } public boolean checkMemory(MemoryModuleType p_21877_, MemoryStatus p_21878_) { Optional> optional = this.memories.get(p_21877_); return optional == null ? false : p_21878_ == MemoryStatus.REGISTERED || p_21878_ == MemoryStatus.VALUE_PRESENT && optional.isPresent() || p_21878_ == MemoryStatus.VALUE_ABSENT && optional.isEmpty(); } public Schedule getSchedule() { return this.schedule; } public void setSchedule(Schedule p_21913_) { this.schedule = p_21913_; } public void setCoreActivities(Set p_21931_) { this.coreActivities = p_21931_; } @Deprecated @VisibleForDebug public Set getActiveActivities() { return this.activeActivities; } @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; } public void useDefaultActivity() { this.setActiveActivity(this.defaultActivity); } public Optional getActiveNonCoreActivity() { for (Activity activity : this.activeActivities) { if (!this.coreActivities.contains(activity)) { return Optional.of(activity); } } return Optional.empty(); } public void setActiveActivityIfPossible(Activity p_21890_) { if (this.activityRequirementsAreMet(p_21890_)) { this.setActiveActivity(p_21890_); } else { this.useDefaultActivity(); } } private void setActiveActivity(Activity p_21961_) { if (!this.isActive(p_21961_)) { this.eraseMemoriesForOtherActivitesThan(p_21961_); this.activeActivities.clear(); this.activeActivities.addAll(this.coreActivities); this.activeActivities.add(p_21961_); } } private void eraseMemoriesForOtherActivitesThan(Activity p_21967_) { for (Activity activity : this.activeActivities) { if (activity != p_21967_) { Set> set = this.activityMemoriesToEraseWhenStopped.get(activity); if (set != null) { for (MemoryModuleType memorymoduletype : set) { this.eraseMemory(memorymoduletype); } } } } } public void updateActivityFromSchedule(long p_21863_, long p_21864_) { if (p_21864_ - this.lastScheduleUpdate > 20L) { this.lastScheduleUpdate = p_21864_; Activity activity = this.getSchedule().getActivityAt((int)(p_21863_ % 24000L)); if (!this.activeActivities.contains(activity)) { this.setActiveActivityIfPossible(activity); } } } public void setActiveActivityToFirstValid(List p_21927_) { for (Activity activity : p_21927_) { if (this.activityRequirementsAreMet(activity)) { this.setActiveActivity(activity); break; } } } public void setDefaultActivity(Activity p_21945_) { this.defaultActivity = p_21945_; } public void addActivity(Activity p_21892_, int p_21893_, ImmutableList> p_21894_) { this.addActivity(p_21892_, this.createPriorityPairs(p_21893_, p_21894_)); } public void addActivityAndRemoveMemoryWhenStopped(Activity p_21896_, int p_21897_, ImmutableList> p_21898_, MemoryModuleType p_21899_) { Set, MemoryStatus>> set = ImmutableSet.of(Pair.of(p_21899_, MemoryStatus.VALUE_PRESENT)); Set> set1 = ImmutableSet.of(p_21899_); this.addActivityAndRemoveMemoriesWhenStopped(p_21896_, this.createPriorityPairs(p_21897_, p_21898_), set, set1); } public void addActivity(Activity p_21901_, ImmutableList>> p_21902_) { this.addActivityAndRemoveMemoriesWhenStopped(p_21901_, p_21902_, ImmutableSet.of(), Sets.newHashSet()); } public void addActivityWithConditions( Activity p_397667_, int p_392126_, ImmutableList> p_397539_, Set, MemoryStatus>> p_391610_ ) { this.addActivityWithConditions(p_397667_, this.createPriorityPairs(p_392126_, p_397539_), p_391610_); } public void addActivityWithConditions( Activity p_21904_, ImmutableList>> p_21905_, Set, MemoryStatus>> p_21906_ ) { this.addActivityAndRemoveMemoriesWhenStopped(p_21904_, p_21905_, p_21906_, Sets.newHashSet()); } public void addActivityAndRemoveMemoriesWhenStopped( Activity p_21908_, ImmutableList>> p_21909_, Set, MemoryStatus>> p_21910_, Set> p_21911_ ) { this.activityRequirements.put(p_21908_, p_21910_); if (!p_21911_.isEmpty()) { this.activityMemoriesToEraseWhenStopped.put(p_21908_, p_21911_); } for (Pair> pair : p_21909_) { this.availableBehaviorsByPriority .computeIfAbsent(pair.getFirst(), p_21917_ -> Maps.newHashMap()) .computeIfAbsent(p_21908_, p_21972_ -> Sets.newLinkedHashSet()) .add((BehaviorControl)pair.getSecond()); } } @VisibleForTesting public void removeAllBehaviors() { this.availableBehaviorsByPriority.clear(); } public boolean isActive(Activity p_21955_) { return this.activeActivities.contains(p_21955_); } public Brain copyWithoutBehaviors() { Brain brain = new Brain<>(this.memories.keySet(), this.sensors.keySet(), ImmutableList.of(), this.codec); for (Entry, Optional>> entry : this.memories.entrySet()) { MemoryModuleType memorymoduletype = entry.getKey(); if (entry.getValue().isPresent()) { brain.memories.put(memorymoduletype, entry.getValue()); } } return brain; } public void tick(ServerLevel p_21866_, E p_21867_) { this.forgetOutdatedMemories(); this.tickSensors(p_21866_, p_21867_); this.startEachNonRunningBehavior(p_21866_, p_21867_); this.tickEachRunningBehavior(p_21866_, p_21867_); } private void tickSensors(ServerLevel p_21950_, E p_21951_) { for (Sensor sensor : this.sensors.values()) { sensor.tick(p_21950_, p_21951_); } } private void forgetOutdatedMemories() { for (Entry, Optional>> entry : this.memories.entrySet()) { if (entry.getValue().isPresent()) { ExpirableValue expirablevalue = (ExpirableValue)entry.getValue().get(); if (expirablevalue.hasExpired()) { this.eraseMemory(entry.getKey()); } expirablevalue.tick(); } } } public void stopAll(ServerLevel p_21934_, E p_21935_) { long i = p_21935_.level().getGameTime(); for (BehaviorControl behaviorcontrol : this.getRunningBehaviors()) { behaviorcontrol.doStop(p_21934_, p_21935_, i); } } private void startEachNonRunningBehavior(ServerLevel p_21958_, E p_21959_) { long i = p_21958_.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(p_21958_, p_21959_, i); } } } } } } private void tickEachRunningBehavior(ServerLevel p_21964_, E p_21965_) { long i = p_21964_.getGameTime(); for (BehaviorControl behaviorcontrol : this.getRunningBehaviors()) { behaviorcontrol.tickOrStop(p_21964_, p_21965_, i); } } private boolean activityRequirementsAreMet(Activity p_21970_) { if (!this.activityRequirements.containsKey(p_21970_)) { return false; } else { for (Pair, MemoryStatus> pair : this.activityRequirements.get(p_21970_)) { MemoryModuleType memorymoduletype = pair.getFirst(); MemoryStatus memorystatus = pair.getSecond(); if (!this.checkMemory(memorymoduletype, memorystatus)) { return false; } } return true; } } private boolean isEmptyCollection(Object p_21919_) { return p_21919_ instanceof Collection && ((Collection)p_21919_).isEmpty(); } ImmutableList>> createPriorityPairs( int p_21860_, ImmutableList> p_21861_ ) { int i = p_21860_; Builder>> builder = ImmutableList.builder(); for (BehaviorControl behaviorcontrol : p_21861_) { builder.add(Pair.of(i++, behaviorcontrol)); } return builder.build(); } static final class MemoryValue { private final MemoryModuleType type; private final Optional> value; static Brain.MemoryValue createUnchecked(MemoryModuleType p_22060_, Optional> p_22061_) { return new Brain.MemoryValue<>(p_22060_, (Optional>)p_22061_); } MemoryValue(MemoryModuleType p_22033_, Optional> p_22034_) { this.type = p_22033_; this.value = p_22034_; } void setMemoryInternal(Brain p_22043_) { p_22043_.setMemoryInternal(this.type, this.value); } public void serialize(DynamicOps p_22048_, RecordBuilder p_22049_) { this.type .getCodec() .ifPresent( p_22053_ -> this.value .ifPresent( p_358912_ -> p_22049_.add( BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().encodeStart(p_22048_, this.type), p_22053_.encodeStart(p_22048_, (ExpirableValue)p_358912_) ) ) ); } } public static final class Provider { private final Collection> memoryTypes; private final Collection>> sensorTypes; private final Codec> codec; Provider(Collection> p_22066_, Collection>> p_22067_) { this.memoryTypes = p_22066_; this.sensorTypes = p_22067_; this.codec = Brain.codec(p_22066_, p_22067_); } public Brain makeBrain(Dynamic p_22074_) { return this.codec .parse(p_22074_) .resultOrPartial(Brain.LOGGER::error) .orElseGet(() -> new Brain<>(this.memoryTypes, this.sensorTypes, ImmutableList.of(), () -> this.codec)); } } }