2301_76275164 2025-07-30 03:15 采纳率: 83.3%
浏览 8
已结题

Minecarft如何实现实用工具置换物品?


package com.GaoHY.handlers;

import com.GaoHY.Init.ItemInit;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.BlockHitResult;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MachineItem extends Item {
    private static final Logger LOGGER = LogManager.getLogger();

    public MachineItem(Properties properties) {
        super(properties);
    }

    @Override
    public InteractionResult useOn(UseOnContext context) {
        Level level = context.getLevel();
        Player player = context.getPlayer();
        if (player == null) return InteractionResult.PASS;

        BlockHitResult hitResult = getPreciseHitResult(player);
        BlockPos pos = hitResult.getBlockPos();
        BlockState state = level.getBlockState(pos);

        if (!state.is(Blocks.WATER)) {
            LOGGER.debug("点击的不是水方块: {}", state.getBlock());
            return InteractionResult.PASS;
        }

        FluidState fluidState = state.getFluidState();
        int waterLevel = state.getValue(LiquidBlock.LEVEL);

        LOGGER.info("检测到水方块 - 位置: {} 水位: {} 流体状态: {}", pos, waterLevel, fluidState.getType());

        if (isValidWaterSource(waterLevel, fluidState)) {
            return handleWaterConversion(level, player, pos);
        }
        return InteractionResult.PASS;
    }

    private BlockHitResult getPreciseHitResult(Player player) {
        return (BlockHitResult) player.pick(5.0, 0.0F, false);
    }

    private boolean isValidWaterSource(int waterLevel, FluidState fluidState) {
        return waterLevel == 0 && fluidState.isSource();
    }

    private InteractionResult handleWaterConversion(Level level, Player player, BlockPos pos) {
        ItemStack eyeStack = findEyeItem(player);
        if (eyeStack.isEmpty()) {
            LOGGER.warn("转换失败:缺少EYE物品");
            return InteractionResult.FAIL;
        }

        if (!level.isClientSide) {
            eyeStack.shrink(1);
            player.addItem(new ItemStack(ItemInit.WATER_GOD_EYE.get()));
            level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.PLAYERS, 1.0F, 1.0F);
            LOGGER.info("成功转换 WATER_GOD_EYE");
        }
        return InteractionResult.sidedSuccess(level.isClientSide);
    }

    private ItemStack findEyeItem(Player player) {
        for (ItemStack stack : player.getInventory().items) {
            if (stack.is(ItemInit.EYE.get())) {
                return stack;
            }
        }
        return ItemStack.EMPTY;
    }
}

我尝试使用物品machine右键水以将eye替换为water_god_eye,但始终无法识别水,而是识别到了水下的泥土,应该如何解决?
minecraft:1.19.2

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-07-30 05:29
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .  
    每日一句正能量,让它带给您好心情:风雨过后的彩虹,才更懂得珍惜的重量。
    .  

    根据你的代码和问题描述,问题出在点击检测逻辑上。当玩家右键点击水方块时,实际上检测到的是水下的方块(如泥土)。以下是解决方案:

    1. 修改getPreciseHitResult方法,确保能正确获取水面点击位置:
    private BlockHitResult getPreciseHitResult(Player player) {
        // 增加检测距离和精确度
        return (BlockHitResult) player.pick(5.0, 1.0F, true); // 第三个参数改为true以检测流体
    }
    
    1. useOn方法中添加流体检测逻辑:
    @Override
    public InteractionResult useOn(UseOnContext context) {
        Level level = context.getLevel();
        Player player = context.getPlayer();
        if (player == null) return InteractionResult.PASS;
    
    
        BlockHitResult hitResult = getPreciseHitResult(player);
        BlockPos pos = hitResult.getBlockPos();
        BlockState state = level.getBlockState(pos);
    
    
        // 先检测流体状态
        FluidState fluidState = level.getFluidState(pos);
        if (fluidState.getType().isSame(Fluids.WATER)) {
            int waterLevel = fluidState.getAmount();
            LOGGER.info("检测到水流体 - 位置: {} 水位: {}", pos, waterLevel);
            
            if (isValidWaterSource(waterLevel, fluidState)) {
                return handleWaterConversion(level, player, pos);
            }
        }
        
        // 再检测水方块(兼容旧版)
        if (state.is(Blocks.WATER)) {
            FluidState blockFluidState = state.getFluidState();
            int waterLevel = state.getValue(LiquidBlock.LEVEL);
            LOGGER.info("检测到水方块 - 位置: {} 水位: {}", pos, waterLevel);
            
            if (isValidWaterSource(waterLevel, blockFluidState)) {
                return handleWaterConversion(level, player, pos);
            }
        }
    
    
        LOGGER.debug("点击的不是有效水方块: {}", state.getBlock());
        return InteractionResult.PASS;
    }
    
    1. 修改isValidWaterSource方法:
    private boolean isValidWaterSource(int waterLevel, FluidState fluidState) {
        // 对于流体状态,8表示源方块
        // 对于方块状态,0表示源方块
        return (waterLevel == 0 || waterLevel == 8) && fluidState.isSource();
    }
    

    关键修改点:

    1. 使用player.pick()时启用流体检测(第三个参数为true)
    2. 同时检测方块状态和流体状态
    3. 调整水位检测逻辑以适应不同情况

    还需要确保在类顶部添加流体导入:

    import net.minecraft.world.level.material.Fluids;
    

    这样修改后,你的工具应该能正确识别水面点击,无论水下有什么方块。当玩家右键点击水面时,会优先检测到水而不是水下的方块。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 8月7日
  • 已采纳回答 7月30日
  • 创建了问题 7月30日