diff --git a/src/generated/resources/.cache/20f5c98dc0fe2d7a53fc98de5b4a9405da0eaab5 b/src/generated/resources/.cache/20f5c98dc0fe2d7a53fc98de5b4a9405da0eaab5 index a43c18df..1eeb715e 100644 --- a/src/generated/resources/.cache/20f5c98dc0fe2d7a53fc98de5b4a9405da0eaab5 +++ b/src/generated/resources/.cache/20f5c98dc0fe2d7a53fc98de5b4a9405da0eaab5 @@ -1,5 +1,5 @@ -// 1.21.1 2025-05-30T15:08:09.0927537 Biome Modifier Registries: ifw -04d4067d7d56c4bcde798c664f47d705dedd5a58 data/ifw/neoforge/biome_modifier/ifw_add_deepslate_spawns.json +// 1.21.1 2025-06-01T01:00:05.8587556 Biome Modifier Registries: ifw +78934f7424c2e156a7114447516ea579a4ce8d24 data/ifw/neoforge/biome_modifier/ifw_add_deepslate_spawns.json d3ce835cbe615798480c31acf5200397159fd125 data/ifw/neoforge/biome_modifier/ifw_add_deep_ores.json 5073fcccdb1b63e1972de71daef79b5d55a8ea59 data/ifw/neoforge/biome_modifier/ifw_add_forest_spawns.json 3f4f805661565e7e8319225b5dd1286a0d82d657 data/ifw/neoforge/biome_modifier/ifw_add_jungle_spawns.json diff --git a/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 b/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 index 6786cc03..18369ebd 100644 --- a/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 +++ b/src/generated/resources/.cache/8c8364f4e83c409ec545b3c2adc7d52ce75bbb78 @@ -1,4 +1,4 @@ -// 1.21.1 2025-05-27T13:31:10.9757849 Tags for minecraft:item mod id vanilla +// 1.21.1 2025-06-01T01:00:05.8607639 Tags for minecraft:item mod id vanilla 20de0e0f4a475259665e322b8fce4c6dc9bd398e data/c/tags/item/buckets/empty.json c8bdd264e6a8f676f43d71732fa26d39c6cb405e data/c/tags/item/buckets/entity_water.json 443176368149964cb5339e006ca44d79e5343a0e data/c/tags/item/buckets/lava.json @@ -6,6 +6,8 @@ c8bdd264e6a8f676f43d71732fa26d39c6cb405e data/c/tags/item/buckets/entity_water.j 5cec9e17dd3afc2804b9f34765750518bc05872d data/c/tags/item/buckets/powder_snow.json 6d22b348406e3916f860cf2e2537b30dd2ca3fea data/c/tags/item/buckets/water.json b0b74270bcd293fe8797cfa8541ee7752d9776f2 data/c/tags/item/strings.json +70241bb1b1f0ffaaabbec1684fc8a614d18d0068 data/c/tags/item/tools.json +816ec6d0fd4ada9f076b1bd208de66958e8aa07d data/c/tags/item/tools/melee_weapon.json 6ea18528bc024774f162ffb9c6936139f8b96cda data/c/tags/item/tools/shear.json 96f50b5a6a3bf46756af20ca13251571d3e39bec data/ifw/tags/item/anvil.json bdd81346635b7b10de96229750d71f72b3168a47 data/ifw/tags/item/battle_axe.json @@ -14,6 +16,7 @@ bdd81346635b7b10de96229750d71f72b3168a47 data/ifw/tags/item/battle_axe.json 91e6fcd988d4016348a8188dcd9e1c6d02f0f8c2 data/ifw/tags/item/dagger.json 6807f04f2cbec6fafec09761de05d1251d5bc484 data/ifw/tags/item/has_enchanting_recipe.json 48b2817554b707fbe61227fa136541f66a3677f5 data/ifw/tags/item/mattock.json +268ef79988c8844763d231174b9d9d019b24c0f0 data/ifw/tags/item/no_mining_tools.json 850a9fa4bd0ea0aba50d76a39b0a8fd594295c92 data/ifw/tags/item/scythe.json 0dc3743e3a00046744151c9359511cb6ff886e8a data/ifw/tags/item/silver_item.json fa031f0a44015a033e136278f19b9714d7246219 data/ifw/tags/item/war_hammer.json diff --git a/src/generated/resources/.cache/e4beba3a8dbdb37f546ef7961fb2493d4be02251 b/src/generated/resources/.cache/e4beba3a8dbdb37f546ef7961fb2493d4be02251 index f4875f04..21b77ad2 100644 --- a/src/generated/resources/.cache/e4beba3a8dbdb37f546ef7961fb2493d4be02251 +++ b/src/generated/resources/.cache/e4beba3a8dbdb37f546ef7961fb2493d4be02251 @@ -1,2 +1,2 @@ -// 1.21.1 2025-05-30T15:51:39.042887 Languages: en_us for mod: ifw -995dd94f9bef0788e34d3e9e4095ddc2d254bfc6 assets/ifw/lang/en_us.json +// 1.21.1 2025-05-30T17:27:06.0841768 Languages: en_us for mod: ifw +cef5a44f9cf4b915e6d95197f8674a63f7e1a0c0 assets/ifw/lang/en_us.json diff --git a/src/generated/resources/assets/ifw/lang/en_us.json b/src/generated/resources/assets/ifw/lang/en_us.json index e447027a..0c261610 100644 --- a/src/generated/resources/assets/ifw/lang/en_us.json +++ b/src/generated/resources/assets/ifw/lang/en_us.json @@ -142,7 +142,7 @@ "entity.ifw.cow": "Cow", "entity.ifw.demon_spider": "Demon Spider", "entity.ifw.ghoul": "Ghoul", - "entity.ifw.hell_hound": "Hellhound", + "entity.ifw.hell_hound": "Hell Hound", "entity.ifw.inferno_creeper": "Inferno Creeper", "entity.ifw.invisible_stalker": "Invisible Stalker", "entity.ifw.phase_spider": "Phase Spider", @@ -294,7 +294,7 @@ "item.ifw.golden_shovel": "Gold Shovel", "item.ifw.golden_sword": "Gold Sword", "item.ifw.golden_war_hammer": "Gold War Hammer", - "item.ifw.hellhound_spawn_egg": "Hellhound Spawn Egg", + "item.ifw.hellhound_spawn_egg": "HellHound Spawn Egg", "item.ifw.ice_cream": "Ice Cream", "item.ifw.inferno_creeper_spawn_egg": "Inferno Creeper Spawn Egg", "item.ifw.invisible_stalker_spawn_egg": "Invisible Stalker Spawn Egg", diff --git a/src/generated/resources/data/c/tags/item/tools.json b/src/generated/resources/data/c/tags/item/tools.json new file mode 100644 index 00000000..61732cc0 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/tools.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#ifw:mattock" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/tools/melee_weapon.json b/src/generated/resources/data/c/tags/item/tools/melee_weapon.json new file mode 100644 index 00000000..a0df0367 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/tools/melee_weapon.json @@ -0,0 +1,9 @@ +{ + "values": [ + "#ifw:battle_axe", + "#ifw:dagger", + "#ifw:scythe", + "#ifw:war_hammer", + "ifw:wooden_club" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ifw/neoforge/biome_modifier/ifw_remove_overworld_features.json b/src/generated/resources/data/ifw/neoforge/biome_modifier/ifw_remove_overworld_features.json index d127ab57..ac2a92f8 100644 --- a/src/generated/resources/data/ifw/neoforge/biome_modifier/ifw_remove_overworld_features.json +++ b/src/generated/resources/data/ifw/neoforge/biome_modifier/ifw_remove_overworld_features.json @@ -7,7 +7,7 @@ "minecraft:patch_melon_sparse" ], "steps": [ - "vegetal_decoration", - "lakes" + "lakes", + "vegetal_decoration" ] } \ No newline at end of file diff --git a/src/generated/resources/data/ifw/tags/item/no_mining_tools.json b/src/generated/resources/data/ifw/tags/item/no_mining_tools.json new file mode 100644 index 00000000..501db982 --- /dev/null +++ b/src/generated/resources/data/ifw/tags/item/no_mining_tools.json @@ -0,0 +1,8 @@ +{ + "values": [ + "#minecraft:swords", + "#ifw:dagger", + "#ifw:scythe", + "ifw:wooden_club" + ] +} \ No newline at end of file diff --git a/src/main/java/huix/infinity/common/core/tag/IFWItemTags.java b/src/main/java/huix/infinity/common/core/tag/IFWItemTags.java index 1160ae7b..462f6565 100644 --- a/src/main/java/huix/infinity/common/core/tag/IFWItemTags.java +++ b/src/main/java/huix/infinity/common/core/tag/IFWItemTags.java @@ -5,7 +5,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; public class IFWItemTags { @@ -19,6 +18,7 @@ public class IFWItemTags { public static final TagKey BUCKETS_STONE = bind("buckets_stone"); public static final TagKey HAS_ENCHANTING_RECIPE = bind("has_enchanting_recipe"); public static final TagKey SILVER_ITEM = bind("silver_item"); + public static final TagKey NO_MINING_TOOLS = bind("no_mining_tools"); public static TagKey bind(String name) { return TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(InfinityWay.MOD_ID, name)); diff --git a/src/main/java/huix/infinity/common/world/entity/ai/DiggerGoal.java b/src/main/java/huix/infinity/common/world/entity/ai/DiggerGoal.java index 36e2360b..66ea3a9b 100644 --- a/src/main/java/huix/infinity/common/world/entity/ai/DiggerGoal.java +++ b/src/main/java/huix/infinity/common/world/entity/ai/DiggerGoal.java @@ -1,321 +1,296 @@ package huix.infinity.common.world.entity.ai; +import huix.infinity.common.core.tag.IFWItemTags; import huix.infinity.common.world.entity.monster.digger.Digger; +import huix.infinity.common.world.item.IFWTieredItem; import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.tags.BlockTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.goal.Goal; -import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; -import net.minecraft.world.entity.ai.goal.WrappedGoal; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.pathfinder.Node; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.neoforged.neoforge.common.Tags; import java.util.EnumSet; public class DiggerGoal extends Goal { - private Digger digger; - private static boolean PLAYER_ATTACKS_RESET_DIGGING = false; - public DiggerGoal(Digger attacker) { - this.digger = attacker; - this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); + private float MAX_DIG_DISTANCE = 3.0f; + private final Digger digger; + private int lastBreakProgress = -1; // 用于追踪上一次的破坏进度 + + public DiggerGoal(Digger digger) { + this.digger = digger; + this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK)); } @Override public boolean canUse() { - // 阻止挖掘的物品检查(保持逻辑不变) - if (this.digger.isHoldingItemThatPreventsDigging()) { + LivingEntity target = this.digger.getTarget(); + if (target == null || !target.isAlive()) { return false; } - boolean hasLineOfSight = this.digger.getTarget() != null && - this.digger.getSensing().hasLineOfSight(this.digger.getTarget()); - - // 生物是否未启用挖掘而且看不见目标 - if (!this.digger.isDiggingEnabled() && !hasLineOfSight) { + if (this.digger.hasLineOfSight(target) && this.digger.isWithinMeleeAttackRange(target)) { return false; } - // 生物挖掘是否会被攻击打断 - if (this.digger.getLastHurtByMobTimestamp() > 0 && PLAYER_ATTACKS_RESET_DIGGING) { - return false; - } + ItemStack tool = this.digger.getMainHandItem(); + if (tool.is(IFWItemTags.NO_MINING_TOOLS)) return false; - // 生物和目标是否在同一位置 - LivingEntity target = this.digger.getTarget(); - if (target == null || this.digger.blockPosition().equals(target.blockPosition())) { - return false; + // 如果已经有挖掘目标,继续使用 + if (digger.getDigTarget() != null) { + return true; } - // 生物是否可以破坏选中方块 - if (this.digger.isDestroyingBlock && - this.digger.canDestroyBlock(this.digger.destroyBlockPos, true)) { + // 寻找可以挖掘的方块 + BlockPos targetBlock = findDiggableBlock(target); + if (targetBlock != null) { + digger.setDigTarget(targetBlock); return true; } + return false; + } - // 在没开始挖掘前有几率放弃挖掘 - if (!this.digger.isDestroyingBlock && - this.digger.getRandom().nextInt(20) != 0) { - return false; - } + private BlockPos findDiggableBlock(LivingEntity target) { + // 获取僵尸和目标之间的距离 + double distanceToTarget = this.digger.distanceToSqr(target); - // 距离检查 - double distance = this.digger.distanceTo(target); - if (distance > 16.0) { - return false; + // 如果目标太远,不考虑挖掘 + if (distanceToTarget > 16.0D) { // 4 blocks squared + return null; } - // 距离超过2时尝试沿目标路径寻找方块 - if (distance * distance > 2.0f) { - BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos( - target.getBlockX(), - target.getBlockY(), - target.getBlockZ() - ); + // 获取到目标的路径 + Path path = this.digger.getNavigation().createPath(target, 0); + if (path == null || path.getEndNode() == null || + path.getEndNode().asBlockPos().equals(digger.blockPosition())) { + // 如果无法找到路径,检查周围可挖掘的方块 + return findNearestDiggableBlock(target.blockPosition()); + } - for (int y = mutablePos.getY(); y >= this.digger.getBlockY(); y--) { - mutablePos.setY(y); - if (this.digger.setBlockToDig(mutablePos, true)) { - return true; + // 检查路径上的障碍物 + for (int i = 0; i < Math.min(path.getNodeCount(), 5); i++) { + Node node = path.getNode(i); + BlockPos pos = new BlockPos(node.x, node.y + 1, node.z); + + // 检查该位置和上方一格的方块(因为是两格高的生物) + if (isDiggableBlock(pos) || isDiggableBlock(pos.above())) { + // 确保方块在挖掘范围内 + if (this.digger.distanceToSqr(Vec3.atCenterOf(pos)) <= MAX_DIG_DISTANCE * MAX_DIG_DISTANCE) { + if (isDiggableBlock(pos) && hasLineOfSight(pos)) { + return pos; + } } } } - // 最大追踪挖掘距离 - double maxDistance = hasLineOfSight ? 8.0 : this.digger.isAggressive() ? 6.0 : 4.0; - if (distance > maxDistance) { - return false; - } + return null; + } - // 如果存在寻路路径,取消挖掘 - Path path = this.digger.getNavigation().createPath(target, 0); - if (path != null && path.canReach()) { - return false; + private BlockPos findNearestDiggableBlock(BlockPos targetPos) { + BlockPos nearest = null; + double nearestDistance = Double.MAX_VALUE; + int diggerY = digger.blockPosition().getY(); + int targetY = targetPos.getY(); + + // 定义Y轴搜索顺序 + int[] ySearchOrder; + + if (diggerY == targetY) { + // 当在同一高度时,从中间向两边搜索 + ySearchOrder = new int[] {1, 0, -1, 2, -2}; + } else if (diggerY < targetY) { + // 当目标在上方时,从上往下搜索 + ySearchOrder = new int[] {2, 1, 0, -1, -2}; + } else { + // 当目标在下方时,从下往上搜索 + ySearchOrder = new int[] {-2, -1, 0, 1, 2}; } - // 如果能够看见目标,且目标在攻击范围内,取消挖掘 - if (this.digger.hasLineOfSight(target) && this.digger.isWithinMeleeAttackRange(target)) { - return false; + int[] xzSearchOrder = new int[] {0, 1, -1, 2, -2}; + + // 在XZ平面上进行搜索 + for (int x : xzSearchOrder) { + for (int z : xzSearchOrder) { + // 按照确定的顺序搜索Y轴 + for (int yOffset : ySearchOrder) { + BlockPos checkPos = targetPos.offset(x, yOffset, z); + + // 检查方块是否在挖掘范围内 + double distance = this.digger.distanceToSqr(Vec3.atCenterOf(checkPos)); + if (distance > MAX_DIG_DISTANCE * MAX_DIG_DISTANCE) { + continue; + } + + // 检查方块是否可挖掘且有视线 + if (isDiggableBlock(checkPos) && hasLineOfSight(checkPos)) { + // 计算到目标的曼哈顿距离 + double manhattanDist = targetPos.distManhattan(checkPos); + if (manhattanDist < nearestDistance) { + nearestDistance = manhattanDist; + nearest = checkPos; + } + } + } + } } - BlockPos targetHeadPos = BlockPos.containing(target.position().add(0, target.getBbHeight(), 0)); - Vec3 targetCenterPos = target.getBoundingBox().getCenter(); + return nearest; + } + private boolean isDiggableBlock(BlockPos pos) { Level level = this.digger.level(); + BlockState state = level.getBlockState(pos); + float defaultDestroyTime = state.getBlock().defaultDestroyTime(); - // 第一部分检测(上方空间) - if (checkUpperSpace(level, targetHeadPos, targetCenterPos)) { - return true; + if (state.isEmpty()) { + return false; } - // 第二部分检测(直接路径) - if (checkPath(level, targetCenterPos)) { + if (defaultDestroyTime <= 1) { return true; } - // 第三部分检测(腿部位置) - return checkLegPath(level, targetCenterPos); + // 检查方块是否可以被当前工具挖掘 + ItemStack tool = this.digger.getMainHandItem(); + + return (tool.getItem() instanceof IFWTieredItem tieredItem && tieredItem.isDamageable(state)) + || tool.isCorrectToolForDrops(state); } - private boolean checkUpperSpace(Level level, BlockPos targetHead, Vec3 targetCenter) { - BlockPos upperPos = targetHead.above(); - if (level.getBlockState(upperPos).isAir()) { - ClipContext context = new ClipContext( - this.digger.getEyePosition(), - targetCenter.add(0, 1, 0), - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - this.digger - ); + private float calculateDiggingSpeed(ItemStack tool, BlockState state, BlockPos pos) { + float baseSpeed = tool.getDestroySpeed(state); + float blockHardness = state.getDestroySpeed(digger.level(), pos); - BlockHitResult hitResult = level.clip(context); - return processHitResult(hitResult, level); + if (blockHardness == -1.0F) { + return 0.0F; // 不可破坏的方块 } - return false; - } - private boolean checkPath(Level level, Vec3 targetCenter) { - ClipContext context = new ClipContext( - this.digger.getEyePosition(), - targetCenter, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - this.digger - ); - - BlockHitResult hitResult = level.clip(context); - return processHitResult(hitResult, level); + // 基础速度除以方块硬度,再加上一个基础值 + return (baseSpeed / (blockHardness * 30.0F)) + 0.005F; } - private boolean checkLegPath(Level world, Vec3 targetCenter) { - // 获取腿部位置 - Vec3 legPos = this.digger.getLegPosition(); - ClipContext context = new ClipContext( - legPos, - targetCenter, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - this.digger - ); - - BlockHitResult hitResult = world.clip(context); - if (hitResult.getType() == HitResult.Type.BLOCK) { - - BlockPos hitPos = hitResult.getBlockPos(); - BlockState state = world.getBlockState(hitPos); + @Override + public void tick() { + BlockPos targetBlock = digger.getDigTarget(); + if (targetBlock == null) return; - if (!isValidBlock(state)) { - return false; - } + // 确保僵尸面向目标方块 + this.digger.getLookControl().setLookAt( + targetBlock.getX() + 0.5, + targetBlock.getY() + 0.5, + targetBlock.getZ() + 0.5 + ); - BlockPos upperPos = hitPos.above(); - if (!world.getBlockState(upperPos).isAir() && !this.digger.blockWillFall(upperPos)) { - return false; - } + // 获取当前进度 + float progress = digger.getDigProgress(); + BlockState blockState = digger.level().getBlockState(targetBlock); + ItemStack stack = digger.getMainHandItem(); + this.MAX_DIG_DISTANCE = 3 + stack.getItem().getReachBonus(); + // 计算挖掘速度 + float speedMultiplier = calculateDiggingSpeed(stack, blockState, targetBlock); + progress += speedMultiplier / 30; + digger.setDigProgress(progress); + + // 计算当前破坏进度(0-9) + int breakProgress = (int) (progress * 10.0F); + + // 当进入新的破坏阶段时摆动手臂 + if (breakProgress > lastBreakProgress) { + swingArm(blockState, targetBlock); + + // 更新方块破坏进度 + digger.level().destroyBlockProgress( + digger.getId(), + targetBlock, + Math.min(breakProgress, 9) + ); - return this.digger.setBlockToDig(hitPos, false); + lastBreakProgress = breakProgress; } - return false; - } - private boolean processHitResult(BlockHitResult hitResult, Level level) { - if (hitResult.getType() == HitResult.Type.BLOCK) { - BlockPos hitPos = hitResult.getBlockPos(); - BlockState state = level.getBlockState(hitPos); - if (isValidBlock(state)) { - BlockPos.MutableBlockPos mutable = hitPos.above().mutable(); - for (int y = hitPos.getY(); y >= this.digger.getBlockY(); y--) { - mutable.setY(y); - if (this.digger.setBlockToDig(mutable, true)) { - return true; - } - } - } + // 完成挖掘 + if (progress >= 1.0F) { + digger.level().destroyBlock(targetBlock, true); + digger.clearDigging(); } - return false; - } - - private boolean isValidBlock(BlockState state) { - return !isRestrictedBlock(state) || - this.digger.isEffectiveTool(state) || - this.digger.isTargetingPlayer(); } - public boolean isRestrictedBlock(BlockState state) { - return state.is(Tags.Blocks.FENCES); - } - - private boolean couldGetCloserByPathing() { - LivingEntity target = this.digger.getTarget(); - if (target == null) return false; - - double distance = this.digger.distanceToSqr(target); - Path path = this.digger.getNavigation().createPath(target, 16); - if (path == null || path.getEndNode() == null) return false; - - Node finalNode = path.getEndNode(); - Vec3 pathPos = new Vec3( - finalNode.x + 0.5, - finalNode.y, - finalNode.z + 0.5 - ); - - return pathPos.distanceToSqr(target.position()) < distance - 4.0; - } - - private boolean couldHitTargetByPathing() { + @Override + public boolean canContinueToUse() { LivingEntity target = this.digger.getTarget(); if (target == null) return false; - Path path = this.digger.getNavigation().createPath(target, 0); - return path != null && path.canReach(); - } - - @Override - public void start() { - this.digger.isDestroyingBlock = true; - } - - @Override - public boolean canContinueToUse() { - if (this.digger.isHoldingItemThatPreventsDigging()) { + if (this.digger.hasLineOfSight(target) && this.digger.isWithinMeleeAttackRange(target)) { return false; } - MeleeAttackGoal attackGoal = (MeleeAttackGoal) this.digger.goalSelector.getAvailableGoals() - .stream() - .filter(g -> g.getGoal() instanceof MeleeAttackGoal) - .findFirst() - .map(WrappedGoal::getGoal) - .orElse(null); + BlockPos targetBlock = digger.getDigTarget(); + if (targetBlock == null) return false; - if (attackGoal != null) { - if (attackGoal.ticksUntilNextAttack > 0) { - attackGoal.ticksUntilNextAttack--; - } - if (this.digger.getTarget() != null && attackGoal.canPerformAttack(this.digger.getTarget())) { - attackGoal.tick(); + Path path = this.digger.getNavigation().createPath(target, 0); + if (path != null && path.getEndNode() != null && !path.getEndNode().asBlockPos().equals(digger.blockPosition())) { + // 如果我们正在定位并且离目标还很远,现在还不用开始挖掘 + double distanceToTarget = this.digger.distanceToSqr(target); + if (distanceToTarget > 4) { return false; } } - if (this.digger.destroyPauseTicks > 0) { - return this.digger.destroyPauseTicks != 1 || !this.couldGetCloserByPathing(); - } - - if (!this.digger.isDestroyingBlock) { - return false; - } - - if (!this.digger.canDestroyBlock(this.digger.destroyBlockPos, true)) { - return false; - } - - if (this.digger.getLastHurtByMobTimestamp() > 0 && PLAYER_ATTACKS_RESET_DIGGING) { - return false; - } + // 检查方块是否可以被挖掘 + return isDiggableBlock(targetBlock) && hasLineOfSight(targetBlock); + } - LivingEntity target = this.digger.getTarget(); - if (target == null) return false; + private boolean hasLineOfSight(BlockPos targetPos) { + Level level = digger.level(); + Vec3 diggerEyes = digger.getEyePosition().add(0, -0.3f, 0); + Vec3 blockCenter = new Vec3( + targetPos.getX() + 0.5, + targetPos.getY() + 0.5, + targetPos.getZ() + 0.5 + ); - if (this.digger.blockPosition().equals(target.blockPosition())) { - return false; - } + // 使用射线追踪检查视线 + BlockHitResult result = level.clip(new ClipContext( + diggerEyes, + blockCenter, + ClipContext.Block.COLLIDER, + ClipContext.Fluid.NONE, + digger + )); - return this.digger.getRandom().nextInt(10) != 0 || !this.couldHitTargetByPathing(); + return result.getBlockPos().equals(targetPos); } - @Override - public void tick() { - Vec3 pos = Vec3.atCenterOf(this.digger.destroyBlockPos); - this.digger.getLookControl().setLookAt( - pos.x, pos.y, pos.z, - (float)(this.digger.getMaxHeadYRot() + 20), - (float)this.digger.getMaxHeadXRot()); - - if (this.digger.destroyPauseTicks > 0) { - this.digger.destroyPauseTicks --; - return; - } - - if (this.digger.destroyBlockCoolOff == 10) { - this.digger.swing(InteractionHand.MAIN_HAND); + private void swingArm(BlockState blockState, BlockPos targetBlock) { + digger.swing(InteractionHand.MAIN_HAND); + Level level = digger.level(); + // 播放方块破坏效果 + if (blockState.is(BlockTags.IMPERMEABLE)) { + level.playSound(null, targetBlock, SoundEvents.GLASS_BREAK, + SoundSource.BLOCKS, 1.0f, 0.8f); + } else { + level.levelEvent(2001, targetBlock, Block.getId(blockState)); } - - if (--this.digger.destroyBlockCoolOff > 0) return; - - this.digger.destroyBlockCoolOff = this.digger.getCoolOffForBlock(); - this.digger.partiallyDestroyBlock(); } @Override public void stop() { - this.digger.cancelBlockDestruction(); + BlockPos targetBlock = digger.getDigTarget(); + if (targetBlock != null) { + // 清除方块破坏进度显示 + digger.level().destroyBlockProgress(digger.getId(), targetBlock, -1); + } + lastBreakProgress = 0; + digger.clearDigging(); } } diff --git a/src/main/java/huix/infinity/common/world/entity/monster/digger/Digger.java b/src/main/java/huix/infinity/common/world/entity/monster/digger/Digger.java index 9a9f0024..caeab854 100644 --- a/src/main/java/huix/infinity/common/world/entity/monster/digger/Digger.java +++ b/src/main/java/huix/infinity/common/world/entity/monster/digger/Digger.java @@ -1,377 +1,59 @@ package huix.infinity.common.world.entity.monster.digger; import huix.infinity.common.world.entity.ai.DiggerGoal; -import huix.infinity.common.world.item.ClubWeapon; -import huix.infinity.common.world.item.IFWDiggerItem; -import huix.infinity.common.world.item.ScytheTool; -import huix.infinity.common.world.item.ShovelTool; -import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.tags.BlockTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.monster.Monster; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.gameevent.GameEvent; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.neoforged.neoforge.common.Tags; import org.jetbrains.annotations.NotNull; -import static net.minecraft.world.level.block.Block.dropResources; - public class Digger extends Monster { - public boolean isDestroyingBlock; - public BlockPos destroyBlockPos; - protected int destroyBlockProgress; - public int destroyBlockCoolOff = 20; - public int destroyPauseTicks; + // 用于存储目标方块位置的 NBT 标签名 + private static final String TARGET_X = "DigTargetX"; + private static final String TARGET_Y = "DigTargetY"; + private static final String TARGET_Z = "DigTargetZ"; + private static final String DIG_PROGRESS = "DigProgress"; + private static final String HAS_TARGET = "HasDigTarget"; + + // 存储当前挖掘目标和进度的字段 + private BlockPos digTarget; + private float digProgress = 0; + protected Digger(EntityType entityType, Level level) { super(entityType, level); this.goalSelector.addGoal(1, new DiggerGoal(this)); } - public boolean isHoldingItemThatPreventsDigging() { - ItemStack handItem = this.getMainHandItem(); - return handItem.is(Tags.Items.MELEE_WEAPON_TOOLS) || - handItem.getItem() instanceof ClubWeapon || handItem.getItem() instanceof ScytheTool; - } - - public boolean isEffectiveTool(BlockState state) { - Item handItem = this.getMainHandItem().getItem(); - if (handItem instanceof IFWDiggerItem ifwDiggerItem) { - return ifwDiggerItem.isDamageable(state); - } - return false; - } - - public boolean isDiggingEnabled() { - return !this.isHoldingItemThatPreventsDigging(); - } - - public boolean blockWillFall(BlockPos pos) { - Block block = this.level().getBlockState(pos).getBlock(); - return block instanceof Fallable || block == Blocks.CACTUS || block instanceof TorchBlock || block == Blocks.SNOW; - } - - public boolean isTargetingPlayer() { - return this.getTarget() instanceof Player; - } - - public void partiallyDestroyBlock() { - ItemStack heldItem = this.getMainHandItem(); - if (!this.canDestroyBlock(destroyBlockPos, true)) { - this.cancelBlockDestruction(); - return; - } -// this.refreshDespawnCounter(-400); - Level level = this.level(); - BlockState blockState = level.getBlockState(destroyBlockPos); - Block block = blockState.getBlock(); - // 处理仙人掌伤害 -// if (block == Blocks.CACTUS && !this.isHoldingItemThatPreventsHandDamage()) { -// DamageSource damageSource = level.damageSources().cactus(); -// this.attackEntityFrom(new DADamage(damageSource, 1.0f)); -// } - if (++this.destroyBlockProgress < 10) { - this.isDestroyingBlock = true; - } else { - this.destroyBlockProgress = -1; - // 玻璃破碎特效 - if (blockState.is(BlockTags.IMPERMEABLE)) { - level.levelEvent(2001, destroyBlockPos, Block.getId(blockState)); - } - - // 方块掉落 - BlockEntity blockEntity = level.getBlockEntity(destroyBlockPos); - dropResources(blockState, level, destroyBlockPos, blockEntity, this, heldItem); - - level.removeBlock(destroyBlockPos, false); - level.gameEvent(this, GameEvent.BLOCK_DESTROY, destroyBlockPos); - - // 处理可能下落的方块 -// if (this.blockWillFall(destroyBlockPos.above())) { -// AABB searchArea = this.getBoundingBox().inflate(3.0, 1.0, 3.0); -// List entities = level.getEntitiesOfClass(PathfinderMob.class, searchArea, -// EntitySelector.NO_CREATIVE_OR_SPECTATOR.and(Entity::isAlive)); -// -// for (PathfinderMob entity : entities) { -// entity.goalSelector.getAvailableGoals().stream() -// .filter(g -> g.getGoal() instanceof MeleeAttackGoal) -// .forEach(g -> { -// // 调整攻击任务计时器(示例,需根据实际 AI 实现调整) -// ((MeleeAttackGoal) g.getGoal()).resetAttackCooldown(); -// }); -// } -// } - // 工具耐久消耗 - Item handItem = heldItem.getItem(); - if (!heldItem.isEmpty()) { - handItem.mineBlock(heldItem, level, blockState, destroyBlockPos, this); - } - - this.isDestroyingBlock = false; - BlockPos abovePos = destroyBlockPos.above(); - BlockState aboveState = level.getBlockState(abovePos); - - // 处理上方方块 - if (aboveState.getBlock() instanceof Fallable) { - this.isDestroyingBlock = true; - this.destroyPauseTicks = 10; - } else if (!aboveState.isAir() && !this.blockWillFall(abovePos)) { - if (destroyBlockPos.getY() == this.getBlockY() && this.canDestroyBlock(abovePos, true)) { - destroyBlockPos = destroyBlockPos.above(); - } else { - destroyBlockPos = destroyBlockPos.below(); - } - this.isDestroyingBlock = true; - this.destroyPauseTicks = 10; - } else if (destroyBlockPos.getY() == this.getBlockY() + 1 && - !level.isEmptyBlock(this.blockPosition().above(2)) && - this.canDestroyBlock(destroyBlockPos.below(), true)) { - this.isDestroyingBlock = true; - this.destroyPauseTicks = 10; - destroyBlockPos = destroyBlockPos.below(); - } - - // 特殊方块处理 -// if (aboveState.getBlock() instanceof UnderminableBlock underminable) { -// underminable.tryToFall(level, abovePos); -// } - } - - level.destroyBlockProgress(this.getId(), destroyBlockPos, destroyBlockProgress); - - // 播放方块破坏效果 - if (blockState.is(BlockTags.IMPERMEABLE)) { - level.playSound(null, destroyBlockPos, SoundEvents.GLASS_BREAK, - SoundSource.BLOCKS, 1.0f, 0.8f); - } else { - level.levelEvent(2001, destroyBlockPos, Block.getId(blockState)); - } - } - - public Vec3 getLegPosition() { - return this.position().add(0, this.getBbHeight() * 0.25F, 0); + // Getter 和 Setter 方法 + public void setDigTarget(BlockPos target) { + this.digTarget = target; } -// protected Vec3 getEyePosForBlockDestroying() { -// return this.getPrimaryPointOfAttack(); -// } - - private boolean hasDownwardsDiggingTool() { - ItemStack held_item = this.getMainHandItem(); - return held_item != null && held_item.getItem() instanceof ShovelTool; - } - - private boolean isBlockClaimedByAnother(BlockPos pos) { - // 使用现代 AABB 构造方式 - AABB searchArea = new AABB( - this.getX() - 4.0, - this.getY() - 4.0, - this.getZ() - 4.0, - this.getX() + 4.0, - this.getY() + 4.0, - this.getZ() + 4.0 - ); - - // 使用类型安全的实体查询 - return this.level().getEntitiesOfClass(Digger.class, searchArea, entity -> - entity != this && - entity.isDestroyingBlock && - entity.destroyBlockPos.equals(pos) - ).stream().findAny().isPresent(); - } - - public boolean canDestroyBlock(BlockPos pos, boolean checkClipping) { - - if (this.isHoldingItemThatPreventsDigging()) { - return false; - } - - final int footY = this.getBlockY(); - final int targetY = pos.getY(); - - // 纵向位置检查 - if (targetY < footY && !this.hasDownwardsDiggingTool()) { - return false; - } - if (targetY > footY + 1) { - return false; - } - - // 距离检查(使用现代向量计算) - final Vec3 entityCenter = this.position() - .add(0, this.getBbHeight() / 2, 0); // 实体中心位置 - final Vec3 blockCenter = Vec3.atCenterOf(pos); - if (entityCenter.distanceTo(blockCenter) > 3.25) { - return false; - } - - // 是否可以看到挖掘方块 - if (checkClipping) { - ClipContext context = new ClipContext( - this.getEyePosition(), - blockCenter, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - this - ); - BlockHitResult result = this.level().clip(context); - - if (result.getType() != HitResult.Type.MISS && - (!pos.equals(result.getBlockPos()))) { - return false; - } - } - - // 获取方块状态 - final BlockState state = this.level().getBlockState(pos); - if (state.isAir() || state.getFluidState().isSource()) { - return false; - } - - // 特殊实体类型处理(土元素) -// if (this instanceof EntityEarthElemental elemental) { -// int harvestLevel = state.getHarvestLevel(); -// return elemental.getBlockHarvestLevel() >= harvestLevel; -// } - - // 工具有效性检查 - ItemStack tool = this.getMainHandItem(); - boolean hasEffectiveTool = !tool.isEmpty() && - /* state.canHarvestBlock(this.level(), pos, this) && */ - tool.isCorrectToolForDrops(state); - - // 白名单材质检查(使用现代标签系统) - boolean isSoftMaterial = state.is(BlockTags.SAND) || - state.is(BlockTags.DIRT) || - state.is(BlockTags.LEAVES) || - state.is(BlockTags.WOOL) || - state.is(BlockTags.IMPERMEABLE) || - state.getBlock() instanceof CropBlock; - - - // 最终判断逻辑 - return (hasEffectiveTool || - !state.requiresCorrectToolForDrops() || -// (this.isFrenzied() && state.getHarvestLevel() < 2) || - isSoftMaterial) && - !this.isBlockClaimedByAnother(pos); + public BlockPos getDigTarget() { + return this.digTarget; } - public boolean setBlockToDig(BlockPos targetPos, boolean checkClipping) { - if (!this.canDestroyBlock(targetPos, checkClipping)) { - return false; - } - - this.isDestroyingBlock = true; - - // 相同目标位置快速返回 - if (targetPos.equals(this.destroyBlockPos)) { - return true; - } - - // 仙人掌特殊处理(使用现代坐标方法) - final BlockPos footPos = this.blockPosition(); - if (targetPos.getY() == footPos.getY() + 1) { - BlockState currentState = this.level().getBlockState(targetPos); - BlockPos belowPos = targetPos.below(); - - if (currentState.is(Blocks.CACTUS) && - this.canDestroyBlock(belowPos, checkClipping)) { - targetPos = belowPos; // 更新目标位置到下方方块 - } - } - - // 重置破坏状态 - this.destroyBlockProgress = -1; - this.destroyBlockPos = targetPos; - return true; + public void setDigProgress(float progress) { + this.digProgress = progress; } - public void cancelBlockDestruction() { - if (!this.isDestroyingBlock) { - return; - } - this.level().destroyBlockProgress(this.getId(), destroyBlockPos, -1); - this.isDestroyingBlock = false; - this.destroyBlockProgress = -1; - this.destroyBlockCoolOff = 20; + public float getDigProgress() { + return this.digProgress; } - public int getCoolOffForBlock() { - // 使用 BlockPos 替代离散坐标 - final BlockPos destroyPos = this.destroyBlockPos; - final Level level = this.level(); - - // 获取方块状态(替代旧版 blockID 获取方式) - final BlockState state = level.getBlockState(destroyPos); - if (state.isAir()) { - return 20; // 默认冷却时间 - } - - // 获取方块硬度(现代 API) - float hardness = state.getDestroySpeed(level, destroyPos); - int coolOff = (int)(150.0f * hardness); - - - // 狂暴状态加速 -// if (this.isFrenzied()) { -// cooloff /= 2; -// } - - // 土元素特殊处理(使用模式匹配) -// if (this instanceof EntityEarthElemental elemental) { -// cooloff = switch (elemental.getClayType()) { -// case NORMAL -> cooloff / 4; -// case HARDENED -> cooloff / 6; -// case SPECIAL -> cooloff / 8; -// default -> cooloff; -// }; -// } - - // 工具加速计算 - ItemStack toolStack = this.getMainHandItem(); - if (!toolStack.isEmpty()) { - float efficiency = toolStack.getDestroySpeed(state); - if (efficiency > 1.0f) { - coolOff = (int) (coolOff / (1.0f + efficiency * 0.5f)); - } - } - - return Math.max(coolOff, 5); // 确保最小冷却时间 + public void clearDigging() { + this.digTarget = null; + this.digProgress = 0; } @Override public void aiStep() { - if (this.isDestroyingBlock) { - if (this.destroyPauseTicks == 0) { - // 使用 BlockPos 并调用 lookAt 方法 - BlockPos targetPos = this.destroyBlockPos; - this.lookAt( - EntityAnchorArgument.Anchor.EYES, - new Vec3(targetPos.getX() + 0.5, targetPos.getY() + 0.5, targetPos.getZ() + 0.5) - ); - if (!this.canDestroyBlock(destroyBlockPos, true)) { - this.cancelBlockDestruction(); - } - } - } else { - this.destroyBlockCoolOff = 20; - this.destroyBlockProgress = -1; + // 如果有挖掘目标但目标方块不再存在或变成了空气,清除挖掘状态 + if (digTarget != null && (level().isOutsideBuildHeight(digTarget) || + level().getBlockState(digTarget).isAir())) { + clearDigging(); } super.aiStep(); } @@ -379,35 +61,38 @@ public void aiStep() { @Override public void addAdditionalSaveData(@NotNull CompoundTag compound) { super.addAdditionalSaveData(compound); - if (this.isDestroyingBlock) { - compound.putBoolean("isDestroyingBlock", true); - compound.putInt("destroy_block_x", this.destroyBlockPos.getX()); - compound.putInt("destroy_block_y", this.destroyBlockPos.getY()); - compound.putInt("destroy_block_z", this.destroyBlockPos.getZ()); - compound.putInt("destroyBlockProgress", this.destroyBlockProgress); - compound.putInt("destroyBlockCoolOff", this.destroyBlockCoolOff); + // 保存是否有挖掘目标 + compound.putBoolean(HAS_TARGET, digTarget != null); + + // 如果有挖掘目标,保存目标位置和进度 + if (digTarget != null) { + compound.putInt(TARGET_X, digTarget.getX()); + compound.putInt(TARGET_Y, digTarget.getY()); + compound.putInt(TARGET_Z, digTarget.getZ()); + compound.putFloat(DIG_PROGRESS, digProgress); } } @Override public void readAdditionalSaveData(@NotNull CompoundTag compound) { super.readAdditionalSaveData(compound); - if (compound.contains("isDestroyingBlock")) { - this.isDestroyingBlock = compound.getBoolean("isDestroyingBlock"); - int destroy_block_x = compound.getInt("destroy_block_x"); - int destroy_block_y = compound.getInt("destroy_block_y"); - int destroy_block_z = compound.getInt("destroy_block_z"); - this.destroyBlockPos = new BlockPos(destroy_block_x, destroy_block_y, destroy_block_z); - - this.destroyBlockProgress = compound.getInt("destroyBlockProgress"); - this.destroyBlockCoolOff = compound.getInt("destroyBlockCoolOff"); + // 读取挖掘目标和进度 + if (compound.getBoolean(HAS_TARGET)) { + int x = compound.getInt(TARGET_X); + int y = compound.getInt(TARGET_Y); + int z = compound.getInt(TARGET_Z); + digTarget = new BlockPos(x, y, z); + digProgress = compound.getFloat(DIG_PROGRESS); } } @Override public void die(@NotNull DamageSource pDamageSource) { - this.cancelBlockDestruction(); + // 死亡时清除挖掘进度显示 + if (digTarget != null) { + level().destroyBlockProgress(getId(), digTarget, -1); + } super.die(pDamageSource); } } diff --git a/src/main/java/huix/infinity/datagen/tag/IFWItemTagsProvider.java b/src/main/java/huix/infinity/datagen/tag/IFWItemTagsProvider.java index 9b4d00fb..8e15442d 100644 --- a/src/main/java/huix/infinity/datagen/tag/IFWItemTagsProvider.java +++ b/src/main/java/huix/infinity/datagen/tag/IFWItemTagsProvider.java @@ -49,6 +49,11 @@ protected void addTags(final HolderLookup.@NotNull Provider provider) { tag(IFWItemTags.WAR_HAMMER).add(IFWItems.adamantium_war_hammer.get(), IFWItems.mithril_war_hammer.get(), IFWItems.ancient_metal_war_hammer.get(), IFWItems.iron_war_hammer.get(), IFWItems.copper_war_hammer.get(), IFWItems.golden_war_hammer.get(), IFWItems.silver_war_hammer.get(), IFWItems.rusted_iron_war_hammer.get()); + tag(Tags.Items.MELEE_WEAPON_TOOLS).addTags(IFWItemTags.BATTLE_AXE, IFWItemTags.DAGGER, IFWItemTags.SCYTHE, IFWItemTags.WAR_HAMMER).add(IFWItems.wooden_club.get()); + tag(Tags.Items.TOOLS).addTags(IFWItemTags.MATTOCK); + + tag(IFWItemTags.NO_MINING_TOOLS).addTags(ItemTags.SWORDS, IFWItemTags.DAGGER, IFWItemTags.SCYTHE).add(IFWItems.wooden_club.get()); + tag(ItemTags.HEAD_ARMOR_ENCHANTABLE).add(IFWItems.copper_helmet.get(), IFWItems.copper_chainmail_helmet.get(), IFWItems.silver_helmet.get(), IFWItems.silver_chainmail_helmet.get(), IFWItems.golden_chainmail_helmet.get(), IFWItems.ancient_metal_helmet.get(), IFWItems.ancient_metal_chainmail_helmet.get() , IFWItems.mithril_helmet.get(), IFWItems.mithril_chainmail_helmet.get(), IFWItems.adamantium_helmet.get(), IFWItems.adamantium_chainmail_helmet.get());