Skip to content

Commit

Permalink
修正了女仆不关门的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
TartaricAcid committed Dec 30, 2023
1 parent e11f149 commit 0283f6d
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private static void registerCoreGoals(Brain<EntityMaid> brain) {
Pair<Integer, BehaviorControl<? super EntityMaid>> look = Pair.of(0, new LookAtTargetSink(45, 90));
Pair<Integer, BehaviorControl<? super EntityMaid>> maidPanic = Pair.of(1, new MaidPanicTask());
Pair<Integer, BehaviorControl<? super EntityMaid>> maidAwait = Pair.of(1, new MaidAwaitTask());
Pair<Integer, BehaviorControl<? super EntityMaid>> interactWithDoor = Pair.of(2, InteractWithDoor.create());
Pair<Integer, BehaviorControl<? super EntityMaid>> interactWithDoor = Pair.of(2, MaidInteractWithDoor.create());
Pair<Integer, BehaviorControl<? super EntityMaid>> walkToTarget = Pair.of(2, new MoveToTargetSink());
Pair<Integer, BehaviorControl<? super EntityMaid>> followOwner = Pair.of(3, new MaidFollowOwnerTask(0.5f, 2));
Pair<Integer, BehaviorControl<? super EntityMaid>> pickupItem = Pair.of(10, new MaidPickupEntitiesTask(EntityMaid::isPickup, 0.6f));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task;

import com.google.common.collect.Sets;
import com.mojang.datafixers.kinds.OptionalBox;
import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.ai.behavior.BehaviorControl;
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder;
import net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.pathfinder.Node;
import net.minecraft.world.level.pathfinder.Path;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableObject;

import javax.annotation.Nullable;
import java.util.*;

public class MaidInteractWithDoor {
private static final int COOLDOWN_BEFORE_RERUNNING_IN_SAME_NODE = 20;
private static final double SKIP_CLOSING_DOOR_IF_FURTHER_AWAY_THAN = 8;
private static final double MAX_DISTANCE_TO_HOLD_DOOR_OPEN_FOR_OTHER_MOBS = 2;

public static BehaviorControl<LivingEntity> create() {
MutableObject<Node> mutableObject = new MutableObject<>();
MutableInt mutableInt = new MutableInt();
return BehaviorBuilder.create((instance) -> instance.group(instance.present(MemoryModuleType.PATH), instance.registered(MemoryModuleType.DOORS_TO_CLOSE),
instance.registered(MemoryModuleType.NEAREST_LIVING_ENTITIES)).apply(instance, (pathMemory, doorToCloseMemory, livingEntityMemory) -> (serverLevel, entity, time) -> {
Path path = instance.get(pathMemory);
Optional<Set<GlobalPos>> doorToClosePos = instance.tryGet(doorToCloseMemory);
if (!path.notStarted() && !path.isDone()) {
if (Objects.equals(mutableObject.getValue(), path.getNextNode())) {
mutableInt.setValue(COOLDOWN_BEFORE_RERUNNING_IN_SAME_NODE);
} else if (mutableInt.decrementAndGet() > 0) {
return false;
}
mutableObject.setValue(path.getNextNode());
Node previousNode = path.getPreviousNode();
Node nextNode = path.getNextNode();
BlockPos previousNodeBlockPos = previousNode.asBlockPos();
BlockState previousNodeBlockState = serverLevel.getBlockState(previousNodeBlockPos);
if (previousNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) {
DoorBlock doorBlock = (DoorBlock) previousNodeBlockState.getBlock();
if (!doorBlock.isOpen(previousNodeBlockState)) {
doorBlock.setOpen(entity, serverLevel, previousNodeBlockState, previousNodeBlockPos, true);
}
doorToClosePos = rememberDoorToClose(doorToCloseMemory, doorToClosePos, serverLevel, previousNodeBlockPos);
}
BlockPos nextNodeBlockPos = nextNode.asBlockPos();
BlockState nextNodeBlockState = serverLevel.getBlockState(nextNodeBlockPos);
if (nextNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) {
DoorBlock doorBlock = (DoorBlock) nextNodeBlockState.getBlock();
if (!doorBlock.isOpen(nextNodeBlockState)) {
doorBlock.setOpen(entity, serverLevel, nextNodeBlockState, nextNodeBlockPos, true);
doorToClosePos = rememberDoorToClose(doorToCloseMemory, doorToClosePos, serverLevel, nextNodeBlockPos);
}
}
doorToClosePos.ifPresent((doorPos) -> closeDoorsThatIHaveOpenedOrPassedThrough(serverLevel, entity, previousNode, nextNode, doorPos, instance.tryGet(livingEntityMemory)));
return true;
} else {
return false;
}
}));
}

public static void closeDoorsThatIHaveOpenedOrPassedThrough(ServerLevel serverLevel, LivingEntity entity, @Nullable Node previous, @Nullable Node next, Set<GlobalPos> doorPositions, Optional<List<LivingEntity>> nearestLivingEntities) {
Iterator<GlobalPos> doorPosIterator = doorPositions.iterator();
while (doorPosIterator.hasNext()) {
GlobalPos globalPos = doorPosIterator.next();
BlockPos blockPos = globalPos.pos();
if ((previous == null || !previous.asBlockPos().equals(blockPos)) && (next == null || !next.asBlockPos().equals(blockPos))) {
if (isDoorTooFarAway(serverLevel, entity, globalPos)) {
doorPosIterator.remove();
} else {
BlockState blockstate = serverLevel.getBlockState(blockPos);
if (!blockstate.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) {
doorPosIterator.remove();
} else {
DoorBlock doorblock = (DoorBlock) blockstate.getBlock();
if (!doorblock.isOpen(blockstate)) {
doorPosIterator.remove();
} else if (areOtherMobsComingThroughDoor(entity, blockPos, nearestLivingEntities)) {
doorPosIterator.remove();
} else {
doorblock.setOpen(entity, serverLevel, blockstate, blockPos, false);
doorPosIterator.remove();
}
}
}
}
}

}

private static boolean areOtherMobsComingThroughDoor(LivingEntity entity, BlockPos pos, Optional<List<LivingEntity>> nearestLivingEntities) {
return nearestLivingEntities.map(entities -> entities.stream()
.filter((livingEntity) -> livingEntity.getType() == entity.getType())
.filter((livingEntity) -> pos.closerToCenterThan(livingEntity.position(), MAX_DISTANCE_TO_HOLD_DOOR_OPEN_FOR_OTHER_MOBS))
.anyMatch((livingEntity) -> isMobComingThroughDoor(livingEntity.getBrain(), pos))).orElse(false);
}

private static boolean isMobComingThroughDoor(Brain<?> brain, BlockPos pos) {
if (!brain.hasMemoryValue(MemoryModuleType.PATH)) {
return false;
} else {
Path path = brain.getMemory(MemoryModuleType.PATH).get();
if (path.isDone()) {
return false;
} else {
Node previousNode = path.getPreviousNode();
if (previousNode == null) {
return false;
} else {
Node nextNode = path.getNextNode();
return pos.equals(previousNode.asBlockPos()) || pos.equals(nextNode.asBlockPos());
}
}
}
}

private static boolean isDoorTooFarAway(ServerLevel level, LivingEntity entity, GlobalPos pos) {
return pos.dimension() != level.dimension() || !pos.pos().closerToCenterThan(entity.position(), SKIP_CLOSING_DOOR_IF_FURTHER_AWAY_THAN);
}

private static Optional<Set<GlobalPos>> rememberDoorToClose(MemoryAccessor<OptionalBox.Mu, Set<GlobalPos>> doorsToClose, Optional<Set<GlobalPos>> doorPositions, ServerLevel level, BlockPos blockPos) {
GlobalPos globalPos = GlobalPos.of(level.dimension(), blockPos);
return Optional.of(doorPositions.map((pos) -> {
pos.add(globalPos);
return pos;
}).orElseGet(() -> {
Set<GlobalPos> posSet = Sets.newHashSet(globalPos);
doorsToClose.set(posSet);
return posSet;
}));
}
}

0 comments on commit 0283f6d

Please sign in to comment.