From 2d8b932274165738394534d57b9c24161f051270 Mon Sep 17 00:00:00 2001 From: Fff <141797114+WhereisFff@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:00:18 -0700 Subject: [PATCH] =?UTF-8?q?fix(button):=20=E4=BF=AE=E5=A4=8D=E5=A4=A7?= =?UTF-8?q?=E7=BA=A2=E6=8C=89=E9=92=AE=E9=81=AE=E6=8C=A1=E8=BE=B9=E7=BC=98?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E4=B8=8E=E6=8C=89=E5=8E=8B=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用实际命中位置进行服务端射线校验,修复按钮可见但底座中心被遮挡时无法按下的问题。 - 按住按钮后等待服务端确认再播放手部动画,并忽略已释放或已切换目标的过期确认。 - fixed #5138 --- .../block/entity/BigRedButtonBlockEntity.java | 5 +- .../event/BigRedButtonInputListener.java | 35 +++++++++--- .../network/BigRedButtonHoldPacket.java | 55 +++++++++++++------ 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/BigRedButtonBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/BigRedButtonBlockEntity.java index ca5372e662..1d338d98c0 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/entity/BigRedButtonBlockEntity.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/BigRedButtonBlockEntity.java @@ -37,12 +37,13 @@ public void onLoad() { } } - public void press(Player player) { + public boolean press(Player player) { if (this.level == null || this.level.isClientSide || !player.isAlive() || player.isSpectator() || player.isShiftKeyDown() - || player.getMainHandItem().is(ModItems.BUILDING_ROD)) return; + || player.getMainHandItem().is(ModItems.BUILDING_ROD)) return false; this.holders.put(player.getUUID(), this.level.getGameTime()); this.setPressed(true); this.level.scheduleTick(this.worldPosition, this.getBlockState().getBlock(), 1); + return true; } public void release(Player player) { diff --git a/src/main/java/dev/dubhe/anvilcraft/client/event/BigRedButtonInputListener.java b/src/main/java/dev/dubhe/anvilcraft/client/event/BigRedButtonInputListener.java index 9e657f3ff3..e4078f580a 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/event/BigRedButtonInputListener.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/event/BigRedButtonInputListener.java @@ -1,6 +1,7 @@ package dev.dubhe.anvilcraft.client.event; import dev.dubhe.anvilcraft.AnvilCraft; +import dev.dubhe.anvilcraft.block.BigRedButtonBlock; import dev.dubhe.anvilcraft.init.block.ModBlocks; import dev.dubhe.anvilcraft.item.BuildingRodItem; import dev.dubhe.anvilcraft.network.BigRedButtonHoldPacket; @@ -11,6 +12,7 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.SubscribeEvent; @@ -27,6 +29,8 @@ public class BigRedButtonInputListener { private static @Nullable BlockPos heldPos; private static @Nullable ClientLevel heldLevel; private static int heartbeatTicks; + private static int holdId; + private static boolean confirmed; private static final float HELD_SWING_PROGRESS = 0.125f; private static @Nullable ClientLevel animationLevel; private static float previousSwingProgress; @@ -36,8 +40,9 @@ public class BigRedButtonInputListener { public static void onUse(InputEvent.InteractionKeyMappingTriggered event) { if (!event.isUseItem()) return; Minecraft minecraft = Minecraft.getInstance(); - BlockPos pos = targetedButton(minecraft); - if (pos == null) return; + BlockHitResult hit = targetedButton(minecraft); + if (hit == null) return; + BlockPos pos = hit.getBlockPos(); event.setCanceled(true); event.setSwingHand(false); if (pos.equals(heldPos) && minecraft.level == heldLevel) return; @@ -45,7 +50,7 @@ public static void onUse(InputEvent.InteractionKeyMappingTriggered event) { heldPos = pos; heldLevel = minecraft.level; heartbeatTicks = 0; - PacketDistributor.sendToServer(new BigRedButtonHoldPacket(pos, true)); + PacketDistributor.sendToServer(new BigRedButtonHoldPacket(pos, hit.getLocation(), true, holdId)); } @SubscribeEvent @@ -68,14 +73,15 @@ public static void onKey(InputEvent.Key event) { public static void onClientTick(ClientTickEvent.Pre event) { if (heldPos == null) return; Minecraft minecraft = Minecraft.getInstance(); + BlockHitResult hit = targetedButton(minecraft); if (minecraft.level != heldLevel || !minecraft.options.keyUse.isDown() - || !heldPos.equals(targetedButton(minecraft))) { + || hit == null || !heldPos.equals(hit.getBlockPos())) { release(); return; } if (++heartbeatTicks >= 5) { heartbeatTicks = 0; - PacketDistributor.sendToServer(new BigRedButtonHoldPacket(heldPos, true)); + PacketDistributor.sendToServer(new BigRedButtonHoldPacket(heldPos, hit.getLocation(), true, holdId)); } } @@ -88,7 +94,16 @@ public static void onAnimationTick(ClientTickEvent.Post event) { swingProgress = 0; } previousSwingProgress = swingProgress; - swingProgress = Mth.approach(swingProgress, heldPos == null ? 0 : HELD_SWING_PROGRESS, HELD_SWING_PROGRESS / 2); + boolean pressed = confirmed && heldPos != null && minecraft.player != null + && minecraft.level == heldLevel && minecraft.level != null + && minecraft.level.getBlockState(heldPos).is(ModBlocks.BIG_RED_BUTTON) + && minecraft.level.getBlockState(heldPos).getValue(BigRedButtonBlock.PRESSED); + swingProgress = Mth.approach(swingProgress, pressed ? HELD_SWING_PROGRESS : 0, HELD_SWING_PROGRESS / 2); + } + + public static void handleHoldResult(BlockPos pos, int id, boolean accepted) { + if (id != holdId || !pos.equals(heldPos) || Minecraft.getInstance().level != heldLevel) return; + confirmed = accepted; } public static float getHandSwingProgress(InteractionHand hand, float partialTick, float vanillaProgress) { @@ -99,21 +114,23 @@ public static float getHandSwingProgress(InteractionHand hand, float partialTick } @Nullable - private static BlockPos targetedButton(Minecraft minecraft) { + private static BlockHitResult targetedButton(Minecraft minecraft) { if (minecraft.level == null || minecraft.player == null || minecraft.screen != null || !minecraft.isWindowActive() || !minecraft.player.isAlive() || minecraft.player.isSpectator() || minecraft.player.isShiftKeyDown() || BuildingRodItem.isHeld(minecraft.player)) return null; if (!(minecraft.hitResult instanceof BlockHitResult hit) || hit.getType() != HitResult.Type.BLOCK) return null; - return minecraft.level.getBlockState(hit.getBlockPos()).is(ModBlocks.BIG_RED_BUTTON) ? hit.getBlockPos() : null; + return minecraft.level.getBlockState(hit.getBlockPos()).is(ModBlocks.BIG_RED_BUTTON) ? hit : null; } private static void release() { Minecraft minecraft = Minecraft.getInstance(); if (heldPos != null && minecraft.level == heldLevel && minecraft.getConnection() != null) { - PacketDistributor.sendToServer(new BigRedButtonHoldPacket(heldPos, false)); + PacketDistributor.sendToServer(new BigRedButtonHoldPacket(heldPos, Vec3.ZERO, false, holdId)); } heldPos = null; heldLevel = null; + holdId++; + confirmed = false; heartbeatTicks = 0; } } diff --git a/src/main/java/dev/dubhe/anvilcraft/network/BigRedButtonHoldPacket.java b/src/main/java/dev/dubhe/anvilcraft/network/BigRedButtonHoldPacket.java index 6477f9dd0f..801bdddd06 100644 --- a/src/main/java/dev/dubhe/anvilcraft/network/BigRedButtonHoldPacket.java +++ b/src/main/java/dev/dubhe/anvilcraft/network/BigRedButtonHoldPacket.java @@ -1,26 +1,32 @@ package dev.dubhe.anvilcraft.network; +import dev.anvilcraft.lib.v2.codec.StreamCodecUtil; import dev.anvilcraft.lib.v2.network.packet.IPacket; -import dev.anvilcraft.lib.v2.network.packet.IServerboundPacket; +import dev.anvilcraft.lib.v2.network.packet.ISensitiveBiPacket; +import dev.anvilcraft.lib.v2.util.Util; import dev.dubhe.anvilcraft.AnvilCraft; -import dev.dubhe.anvilcraft.block.BigRedButtonBlock; import dev.dubhe.anvilcraft.block.entity.BigRedButtonBlockEntity; -import io.netty.buffer.ByteBuf; +import dev.dubhe.anvilcraft.client.event.BigRedButtonInputListener; import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ClipContext; +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.network.PacketDistributor; -public record BigRedButtonHoldPacket(BlockPos pos, boolean held) implements IServerboundPacket { +public record BigRedButtonHoldPacket(BlockPos pos, Vec3 hitLocation, boolean held, int holdId) implements ISensitiveBiPacket { public static final Type TYPE = IPacket.type(AnvilCraft.of("big_red_button_hold")); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( BlockPos.STREAM_CODEC, BigRedButtonHoldPacket::pos, + StreamCodecUtil.VEC3, BigRedButtonHoldPacket::hitLocation, ByteBufCodecs.BOOL, BigRedButtonHoldPacket::held, + ByteBufCodecs.VAR_INT, BigRedButtonHoldPacket::holdId, BigRedButtonHoldPacket::new ); @@ -29,21 +35,38 @@ public Type type() { return TYPE; } + @Override + public void handleOnClient(Player player) { + BigRedButtonInputListener.handleHoldResult(this.pos, this.holdId, this.held); + } + @Override public void handleOnServer(Player player) { - if (!player.level().hasChunkAt(this.pos)) return; - if (!(player.level().getBlockEntity(this.pos) instanceof BigRedButtonBlockEntity button)) return; - if (!this.held) { + boolean accepted = this.updateButton(player); + PacketDistributor.sendToPlayer( + Util.cast(player), new BigRedButtonHoldPacket(this.pos, this.hitLocation, accepted, this.holdId) + ); + } + + private boolean updateButton(Player player) { + if (!player.level().hasChunkAt(this.pos)) return false; + if (!(player.level().getBlockEntity(this.pos) instanceof BigRedButtonBlockEntity button)) return false; + if (!this.held || !this.canPress(player)) { button.release(player); - return; + return false; } - if (!player.isAlive() || player.isSpectator() || !player.canInteractWithBlock(this.pos, 1.0)) return; - Vec3 target = this.pos.getCenter().relative(button.getBlockState().getValue(BigRedButtonBlock.FACING), -0.375); - HitResult hit = player.level().clip(new ClipContext( - player.getEyePosition(), target, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player + return button.press(player); + } + + private boolean canPress(Player player) { + if (!player.isAlive() || player.isSpectator() || !player.canInteractWithBlock(this.pos, 1.0)) return false; + if (!Double.isFinite(this.hitLocation.x) || !Double.isFinite(this.hitLocation.y) || !Double.isFinite(this.hitLocation.z) + || !new AABB(this.pos).inflate(1.0E-5).contains(this.hitLocation)) return false; + Vec3 eye = player.getEyePosition(); + Vec3 target = this.hitLocation.add(this.hitLocation.subtract(eye).normalize().scale(1.0E-4)); + BlockHitResult hit = player.level().clip(new ClipContext( + eye, target, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player )); - if (!(hit instanceof BlockHitResult blockHit) || hit.getType() != HitResult.Type.BLOCK - || !blockHit.getBlockPos().equals(this.pos)) return; - button.press(player); + return hit.getType() == HitResult.Type.BLOCK && hit.getBlockPos().equals(this.pos); } }