diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java index 53672ff9e..3124cded5 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java @@ -6,13 +6,19 @@ import net.minecraft.core.GlobalPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.behavior.Behavior; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.FenceGateBlock; +import net.minecraft.world.level.block.LevelEvent; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.pathfinder.Node; import net.minecraft.world.level.pathfinder.Path; @@ -57,43 +63,55 @@ protected void start(ServerLevel serverWorld, LivingEntity entity, long gameTime this.lastCheckedNode = path.getNextNode(); Node previousNode = path.getPreviousNode(); Node nextNode = path.getNextNode(); - BlockPos blockpos = previousNode.asBlockPos(); - BlockState blockstate = serverWorld.getBlockState(blockpos); - if (blockstate.is(BlockTags.WOODEN_DOORS)) { - DoorBlock doorblock = (DoorBlock) blockstate.getBlock(); - if (!doorblock.isOpen(blockstate)) { - doorblock.setOpen(entity, serverWorld, blockstate, blockpos, true); + + BlockPos previousPos = previousNode.asBlockPos(); + BlockState previousBlockState = serverWorld.getBlockState(previousPos); + if (previousBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { + DoorBlock doorblock = (DoorBlock) previousBlockState.getBlock(); + if (!doorblock.isOpen(previousBlockState)) { + doorblock.setOpen(entity, serverWorld, previousBlockState, previousPos, true); + } + this.rememberDoorToClose(serverWorld, entity, previousPos); + } else if (previousBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { + if (!previousBlockState.getValue(FenceGateBlock.OPEN)) { + setFenceGate(entity, serverWorld, previousBlockState, previousPos, true); } - this.rememberDoorToClose(serverWorld, entity, blockpos); + this.rememberDoorToClose(serverWorld, entity, previousPos); } - BlockPos blockPos = nextNode.asBlockPos(); - BlockState blockState = serverWorld.getBlockState(blockPos); - if (blockState.is(BlockTags.WOODEN_DOORS)) { - DoorBlock doorBlock = (DoorBlock) blockState.getBlock(); - if (!doorBlock.isOpen(blockState)) { - doorBlock.setOpen(entity, serverWorld, blockState, blockPos, true); - this.rememberDoorToClose(serverWorld, entity, blockPos); + + + BlockPos nextPos = nextNode.asBlockPos(); + BlockState nextBlockState = serverWorld.getBlockState(nextPos); + if (nextBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { + DoorBlock doorBlock = (DoorBlock) nextBlockState.getBlock(); + if (!doorBlock.isOpen(nextBlockState)) { + doorBlock.setOpen(entity, serverWorld, nextBlockState, nextPos, true); + this.rememberDoorToClose(serverWorld, entity, nextPos); + } + } else if (nextBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { + if (!nextBlockState.getValue(FenceGateBlock.OPEN)) { + setFenceGate(entity, serverWorld, nextBlockState, nextPos, true); + this.rememberDoorToClose(serverWorld, entity, nextPos); } } + closeDoorsThatIHaveOpenedOrPassedThrough(serverWorld, entity, previousNode, nextNode); } - public static void closeDoorsThatIHaveOpenedOrPassedThrough(ServerLevel serverWorld, LivingEntity entity, @Nullable Node pathPoint, @Nullable Node pathPoint1) { + public static void closeDoorsThatIHaveOpenedOrPassedThrough(ServerLevel serverWorld, LivingEntity entity, @Nullable Node previousNode, @Nullable Node nextNode) { Brain brain = entity.getBrain(); if (brain.hasMemoryValue(MemoryModuleType.DOORS_TO_CLOSE)) { Iterator iterator = brain.getMemory(MemoryModuleType.DOORS_TO_CLOSE).get().iterator(); while (iterator.hasNext()) { GlobalPos globalpos = iterator.next(); BlockPos blockpos = globalpos.pos(); - if ((pathPoint == null || !pathPoint.asBlockPos().equals(blockpos) || (pathPoint1 != null && entity.blockPosition().equals(pathPoint1.asBlockPos()))) - && (pathPoint1 == null || !pathPoint1.asBlockPos().equals(blockpos))) { + if ((previousNode == null || !previousNode.asBlockPos().equals(blockpos) || (nextNode != null && entity.blockPosition().equals(nextNode.asBlockPos()))) + && (nextNode == null || !nextNode.asBlockPos().equals(blockpos))) { if (isDoorTooFarAway(serverWorld, entity, globalpos)) { iterator.remove(); } else { BlockState blockstate = serverWorld.getBlockState(blockpos); - if (!blockstate.is(BlockTags.WOODEN_DOORS)) { - iterator.remove(); - } else { + if (blockstate.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { DoorBlock doorblock = (DoorBlock) blockstate.getBlock(); if (!doorblock.isOpen(blockstate)) { iterator.remove(); @@ -103,6 +121,16 @@ public static void closeDoorsThatIHaveOpenedOrPassedThrough(ServerLevel serverWo doorblock.setOpen(entity, serverWorld, blockstate, blockpos, false); iterator.remove(); } + } else if ((blockstate.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock))) { + if (!blockstate.getValue(FenceGateBlock.OPEN)) { + iterator.remove(); + } else if (areOtherMobsComingThroughDoor(serverWorld, entity, blockpos)) { + iterator.remove(); + } else { + setFenceGate(entity, serverWorld, blockstate, blockpos, false); + } + } else { + iterator.remove(); } } } @@ -126,12 +154,12 @@ private static boolean isMobComingThroughDoor(ServerLevel serverWorld, LivingEnt if (path.isDone()) { return false; } else { - Node pathpoint = path.getPreviousNode(); - if (pathpoint == null) { + Node previousNode = path.getPreviousNode(); + if (previousNode == null) { return false; } else { Node nextNode = path.getNextNode(); - return blockPos.equals(pathpoint.asBlockPos()) || blockPos.equals(nextNode.asBlockPos()); + return blockPos.equals(previousNode.asBlockPos()) || blockPos.equals(nextNode.asBlockPos()); } } } @@ -150,4 +178,10 @@ private void rememberDoorToClose(ServerLevel serverWorld, LivingEntity entity, B brain.setMemory(MemoryModuleType.DOORS_TO_CLOSE, Sets.newHashSet(globalpos)); } } + + private static void setFenceGate(@Nullable Entity entity, Level serverLevel, BlockState blockstate, BlockPos blockPos, boolean isOpen) { + serverLevel.setBlock(blockPos, blockstate.setValue(FenceGateBlock.OPEN, isOpen), Block.UPDATE_CLIENTS | Block.UPDATE_IMMEDIATE); + serverLevel.levelEvent(null, isOpen ? LevelEvent.SOUND_OPEN_FENCE_GATE : LevelEvent.SOUND_CLOSE_FENCE_GATE, blockPos, 0); + serverLevel.gameEvent(entity, isOpen ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, blockPos); + } } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java new file mode 100644 index 000000000..b004c5993 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java @@ -0,0 +1,74 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.ai.navigation; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.FenceGateBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.pathfinder.BlockPathTypes; +import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; + +/** + * 该方法仅修改了栅栏门的寻路判断 + */ +public class MaidNodeEvaluator extends WalkNodeEvaluator { + @Override + public BlockPathTypes getBlockPathType(BlockGetter level, int pX, int pY, int pZ) { + return getMaidBlockPathTypeStatic(level, new BlockPos.MutableBlockPos(pX, pY, pZ)); + } + + private static BlockPathTypes getMaidBlockPathTypeStatic(BlockGetter level, BlockPos.MutableBlockPos pos) { + int x = pos.getX(); + int y = pos.getY(); + int z = pos.getZ(); + + BlockPathTypes type = getMaidBlockPathTypeRaw(level, pos); + if (type == BlockPathTypes.OPEN && y >= level.getMinBuildHeight() + 1) { + BlockPathTypes typeBelow = getMaidBlockPathTypeRaw(level, pos.set(x, y - 1, z)); + + type = typeBelow != BlockPathTypes.WALKABLE + && typeBelow != BlockPathTypes.OPEN + && typeBelow != BlockPathTypes.WATER + && typeBelow != BlockPathTypes.LAVA ? BlockPathTypes.WALKABLE : BlockPathTypes.OPEN; + + if (typeBelow == BlockPathTypes.DAMAGE_FIRE) { + type = BlockPathTypes.DAMAGE_FIRE; + } + + if (typeBelow == BlockPathTypes.DAMAGE_CACTUS) { + type = BlockPathTypes.DAMAGE_CACTUS; + } + + if (typeBelow == BlockPathTypes.DAMAGE_OTHER) { + type = BlockPathTypes.DAMAGE_OTHER; + } + + if (typeBelow == BlockPathTypes.STICKY_HONEY) { + type = BlockPathTypes.STICKY_HONEY; + } + + if (typeBelow == BlockPathTypes.POWDER_SNOW) { + type = BlockPathTypes.DANGER_POWDER_SNOW; + } + } + + if (type == BlockPathTypes.WALKABLE) { + type = checkNeighbourBlocks(level, pos.set(x, y, z), type); + } + + return type; + } + + private static BlockPathTypes getMaidBlockPathTypeRaw(BlockGetter level, BlockPos pos) { + BlockState blockState = level.getBlockState(pos); + BlockPathTypes pathType = blockState.getBlockPathType(level, pos, null); + if (pathType != null) { + return pathType; + } else if (blockState.isAir()) { + return BlockPathTypes.OPEN; + } else if (blockState.getBlock() instanceof FenceGateBlock) { + return blockState.getValue(FenceGateBlock.OPEN) ? BlockPathTypes.DOOR_OPEN : BlockPathTypes.DOOR_WOOD_CLOSED; + } else { + return WalkNodeEvaluator.getBlockPathTypeRaw(level, pos); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidPathNavigation.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidPathNavigation.java new file mode 100644 index 000000000..4030cce05 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidPathNavigation.java @@ -0,0 +1,23 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.ai.navigation; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.pathfinder.BlockPathTypes; +import net.minecraft.world.level.pathfinder.PathFinder; + +public class MaidPathNavigation extends GroundPathNavigation { + public MaidPathNavigation(Mob mob, Level level) { + super(mob, level); + this.mob.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); + } + + @Override + protected PathFinder createPathFinder(int range) { + this.nodeEvaluator = new MaidNodeEvaluator(); + this.nodeEvaluator.setCanOpenDoors(true); + this.nodeEvaluator.setCanPassDoors(true); + this.nodeEvaluator.setCanFloat(true); + return new PathFinder(this.nodeEvaluator, range); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/package-info.java new file mode 100644 index 000000000..a7c330b2a --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.entity.ai.navigation; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java index a54956ca4..52cd27c4e 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java @@ -17,6 +17,7 @@ import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.MaidBrain; import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.MaidSchedule; +import com.github.tartaricacid.touhoulittlemaid.entity.ai.navigation.MaidPathNavigation; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.*; import com.github.tartaricacid.touhoulittlemaid.entity.chatbubble.ChatBubbleManger; import com.github.tartaricacid.touhoulittlemaid.entity.chatbubble.ChatText; @@ -80,7 +81,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; +import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.monster.CrossbowAttackMob; import net.minecraft.world.entity.player.Player; @@ -101,7 +102,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; @@ -204,9 +204,6 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai protected EntityMaid(EntityType type, Level world) { super(type, world); - ((GroundPathNavigation) this.getNavigation()).setCanOpenDoors(true); - this.getNavigation().setCanFloat(true); - this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); this.favorabilityManager = new FavorabilityManager(this); this.scriptBookManager = new MaidScriptBookManager(); this.schedulePos = new SchedulePos(BlockPos.ZERO, world.dimension().location()); @@ -255,6 +252,11 @@ protected void defineSynchedData() { this.entityData.define(GAME_SKILL, new CompoundTag()); } + @Override + protected PathNavigation createNavigation(Level levelIn) { + return new MaidPathNavigation(this, levelIn); + } + @Override @SuppressWarnings("all") public Brain getBrain() {