package net.minecraft.world.entity.ai.behavior; import com.mojang.datafixers.util.Pair; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; public class GateBehavior implements BehaviorControl { private final Map, MemoryStatus> entryCondition; private final Set> exitErasedMemories; private final GateBehavior.OrderPolicy orderPolicy; private final GateBehavior.RunningPolicy runningPolicy; private final ShufflingList> behaviors = new ShufflingList<>(); private Behavior.Status status = Behavior.Status.STOPPED; public GateBehavior( final Map, MemoryStatus> entryCondition, final Set> exitErasedMemories, final GateBehavior.OrderPolicy orderPolicy, final GateBehavior.RunningPolicy runningPolicy, final List, Integer>> behaviors ) { this.entryCondition = entryCondition; this.exitErasedMemories = exitErasedMemories; this.orderPolicy = orderPolicy; this.runningPolicy = runningPolicy; behaviors.forEach(entry -> this.behaviors.add((BehaviorControl)entry.getFirst(), (Integer)entry.getSecond())); } @Override public Behavior.Status getStatus() { return this.status; } @Override public Set> getRequiredMemories() { Set> memories = new HashSet(this.entryCondition.keySet()); for (BehaviorControl behavior : this.behaviors) { memories.addAll(behavior.getRequiredMemories()); } return memories; } private boolean hasRequiredMemories(final E body) { for (Entry, MemoryStatus> entry : this.entryCondition.entrySet()) { MemoryModuleType memoryType = (MemoryModuleType)entry.getKey(); MemoryStatus requiredStatus = (MemoryStatus)entry.getValue(); if (!body.getBrain().checkMemory(memoryType, requiredStatus)) { return false; } } return true; } @Override public final boolean tryStart(final ServerLevel level, final E body, final long timestamp) { if (this.hasRequiredMemories(body)) { this.status = Behavior.Status.RUNNING; this.orderPolicy.apply(this.behaviors); this.runningPolicy.apply(this.behaviors.stream(), level, body, timestamp); return true; } else { return false; } } @Override public final void tickOrStop(final ServerLevel level, final E body, final long timestamp) { this.behaviors.stream().filter(goal -> goal.getStatus() == Behavior.Status.RUNNING).forEach(goal -> goal.tickOrStop(level, body, timestamp)); if (this.behaviors.stream().noneMatch(g -> g.getStatus() == Behavior.Status.RUNNING)) { this.doStop(level, body, timestamp); } } @Override public final void doStop(final ServerLevel level, final E body, final long timestamp) { this.status = Behavior.Status.STOPPED; this.behaviors.stream().filter(goal -> goal.getStatus() == Behavior.Status.RUNNING).forEach(goal -> goal.doStop(level, body, timestamp)); this.exitErasedMemories.forEach(body.getBrain()::eraseMemory); } @Override public String debugString() { Set runningBehaviours = (Set)this.behaviors .stream() .filter(goal -> goal.getStatus() == Behavior.Status.RUNNING) .map(b -> b.getClass().getSimpleName()) .collect(Collectors.toSet()); return this.getClass().getSimpleName() + ": " + runningBehaviours; } public static enum OrderPolicy { ORDERED(t -> {}), SHUFFLED(ShufflingList::shuffle); private final Consumer> consumer; private OrderPolicy(final Consumer> consumer) { this.consumer = consumer; } public void apply(final ShufflingList list) { this.consumer.accept(list); } } public static enum RunningPolicy { RUN_ONE { @Override public void apply(final Stream> behaviors, final ServerLevel level, final E body, final long timestamp) { behaviors.filter(goal -> goal.getStatus() == Behavior.Status.STOPPED).filter(goal -> goal.tryStart(level, body, timestamp)).findFirst(); } }, TRY_ALL { @Override public void apply(final Stream> behaviors, final ServerLevel level, final E body, final long timestamp) { behaviors.filter(goal -> goal.getStatus() == Behavior.Status.STOPPED).forEach(goal -> goal.tryStart(level, body, timestamp)); } }; public abstract void apply( final Stream> behaviors, final ServerLevel level, final E body, final long timestamp ); } }