XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

MyDimension

【Java】我的维度模组

公开
关注 0 Fork 0 Star 0
UTF-8
package com.xfestudio.mydimension.item;

import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.xfestudio.mydimension.builder.BuilderMode;
import com.xfestudio.mydimension.builder.BuilderInteractionPolicy;
import com.xfestudio.mydimension.builder.BuilderNetworkBridge;
import com.xfestudio.mydimension.builder.BuilderOperationManager;
import com.xfestudio.mydimension.builder.BuilderRuntime;
import com.xfestudio.mydimension.builder.RealmwrightData;
import com.xfestudio.mydimension.builder.ResonantAnchorTarget;
import com.xfestudio.mydimension.client.builder.RealmwrightScepterClientExtensions;
import com.xfestudio.mydimension.config.BuilderConfig;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;

import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;

public final class RealmwrightScepterItem extends Item {
    private static final UUID REACH_MODIFIER_ID = UUID.fromString("6db36f7a-5c3c-4e53-91d3-dced67201f45");

    public RealmwrightScepterItem(Properties properties) {
        super(properties.stacksTo(1));
    }

    @Override
    public void initializeClient(Consumer<IClientItemExtensions> consumer) {
        RealmwrightScepterClientExtensions.initialize(consumer);
    }

    @Override
    public InteractionResult useOn(UseOnContext context) {
        Player player = context.getPlayer();
        if (player == null || context.getHand() != InteractionHand.MAIN_HAND) return InteractionResult.PASS;
        boolean shiftDown = player.isShiftKeyDown();
        BlockEntity blockEntity = context.getLevel().getBlockEntity(context.getClickedPos());
        if (!shiftDown && blockEntity instanceof ResonantAnchorTarget) {
            if (context.getLevel().isClientSide()) return InteractionResult.SUCCESS;
            return bindAnchor((ServerPlayer) player, context.getItemInHand(),
                    (ResonantAnchorTarget) blockEntity);
        }
        // Physical Shift overrides are sent by BuilderClientEvents with an explicit packet bit.
        // The ordinary vanilla Item#useOn packet carries only the remappable sneak state, so it
        // must never bypass an interaction-priority block on its own.
        if (BuilderInteractionPolicy.prioritizesBlock(
                context.getLevel().getBlockState(context.getClickedPos()))) {
            return InteractionResult.PASS;
        }
        if (context.getLevel().isClientSide()) return InteractionResult.SUCCESS;
        ServerPlayer serverPlayer = (ServerPlayer) player;
        ItemStack scepter = context.getItemInHand();
        RealmwrightData.ensureId(scepter);
        if (!BuilderRuntime.settings().enabled()) {
            player.displayClientMessage(Component.translatable("message.mydimension.builder.disabled"), true);
            return InteractionResult.FAIL;
        }
        net.minecraft.world.phys.BlockHitResult authoritativeHit = new net.minecraft.world.phys.BlockHitResult(
                context.getClickLocation(), context.getClickedFace(), context.getClickedPos(), context.isInside());
        BuilderOperationManager.Result result = BuilderOperationManager.executeSurface(serverPlayer, scepter,
                authoritativeHit);
        if (!result.accepted() && result.rejectionKey() != null) {
            player.displayClientMessage(Component.translatable(result.rejectionKey()), true);
        }
        if (result.shouldSynchronize()) BuilderNetworkBridge.sync(serverPlayer);
        return result.accepted() ? InteractionResult.CONSUME : InteractionResult.FAIL;
    }

    @Override
    public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
        ItemStack stack = player.getItemInHand(hand);
        if (hand != InteractionHand.MAIN_HAND) return InteractionResultHolder.pass(stack);
        return InteractionResultHolder.pass(stack);
    }

    private static InteractionResult bindAnchor(ServerPlayer player, ItemStack scepter,
                                                ResonantAnchorTarget target) {
        RealmwrightData.ensureId(scepter);
        if (!BuilderRuntime.settings().enabled()) {
            player.displayClientMessage(Component.translatable("message.mydimension.builder.disabled"), true);
            return InteractionResult.FAIL;
        }
        if (!target.mayUse(player)) {
            player.displayClientMessage(Component.translatable("message.mydimension.builder.anchor_forbidden"), true);
            return InteractionResult.FAIL;
        }
        boolean bound = RealmwrightData.bind(scepter, target.anchorId(), BuilderConfig.MAX_BOUND_ANCHORS.get());
        player.displayClientMessage(Component.translatable(bound
                ? "message.mydimension.builder.anchor_bound"
                : "message.mydimension.builder.anchor_already_bound"), true);
        BuilderNetworkBridge.sync(player);
        return InteractionResult.CONSUME;
    }

    @Override
    public void inventoryTick(ItemStack stack, Level level, net.minecraft.world.entity.Entity entity,
                              int slot, boolean selected) {
        if (!level.isClientSide()) RealmwrightData.ensureId(stack);
        super.inventoryTick(stack, level, entity, slot, selected);
    }

    @Override
    public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlot slot, ItemStack stack) {
        if (slot != EquipmentSlot.MAINHAND || !BuilderRuntime.settings().enabled()) {
            return super.getAttributeModifiers(slot, stack);
        }
        double amount = Math.max(0.0D, BuilderRuntime.settings().blockReach() - 4.5D);
        ImmutableMultimap.Builder<Attribute, AttributeModifier> result = ImmutableMultimap.builder();
        result.putAll(super.getAttributeModifiers(slot, stack));
        result.put(ForgeMod.BLOCK_REACH.get(), new AttributeModifier(REACH_MODIFIER_ID,
                "Realmwright block reach", amount, AttributeModifier.Operation.ADDITION));
        return result.build();
    }

    @Override
    public boolean onLeftClickEntity(ItemStack stack, Player player, Entity entity) {
        return true; // The scepter never extends or performs entity attacks.
    }

    @Override
    public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip,
                                TooltipFlag flag) {
        BuilderMode mode = RealmwrightData.mode(stack);
        tooltip.add(Component.translatable("tooltip.mydimension.realmwright_scepter.mode",
                        Component.translatable(mode == BuilderMode.BUILD
                                ? "gui.mydimension.builder.mode.build" : "gui.mydimension.builder.mode.demolish"))
                .withStyle(mode == BuilderMode.BUILD ? ChatFormatting.AQUA : ChatFormatting.RED));
        tooltip.add(Component.translatable("tooltip.mydimension.realmwright_scepter.menu")
                .withStyle(ChatFormatting.GRAY));
        if (!BuilderRuntime.settings().enabled()) {
            tooltip.add(Component.translatable("tooltip.mydimension.realmwright_scepter.disabled")
                    .withStyle(ChatFormatting.RED));
        }
    }
}