From f9adaeff007b3566b51c7b8551d7b9c7532fc9aa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 12 Jun 2025 02:32:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E7=BE=8E=E7=82=B9=E7=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/FlintAndSteelItemBehavior.java | 132 +++++++++++------- .../plugin/user/BukkitServerPlayer.java | 6 + .../core/entity/player/Player.java | 3 + 3 files changed, 94 insertions(+), 47 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index 66b918a98..03b3b822a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -21,6 +21,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -48,65 +49,102 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { return InteractionResult.PASS; } } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to run BaseFireBlock$canBePlacedAt", e); + CraftEngine.instance().logger().warn("Failed to call BaseFireBlock$canBePlacedAt", e); + return InteractionResult.PASS; + } + + // 判断点击的方块是否可燃 + BlockData clickedBlockData = block.getBlockData(); + Object clickedBlockState = BlockStateUtils.blockDataToBlockState(clickedBlockData); + boolean isClickedBlockBurnable; + try { + isClickedBlockBurnable = BlockStateUtils.isBurnable(clickedBlockState) || + (context.getClickedFace() == Direction.UP && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + clickedBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); return InteractionResult.PASS; } net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer(); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); - if (state == null || state.isEmpty()) { - return InteractionResult.PASS; - } else { - // 玩家交互目标是自定义方块 - if (context.getClickedFace() == Direction.UP) { - // 客户端层面必须可交互 - if (!InteractUtils.isInteractable((Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item) context.getItem())) { - return InteractionResult.PASS; - } - // 且没有shift - if (!player.isSecondaryUseActive()) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - } + // 点击对象直接可燃,则忽略 + if (isClickedBlockBurnable) { + int stateId = BlockStateUtils.blockStateToId(clickedBlockState); + if (BlockStateUtils.isVanillaBlock(stateId)) { + return InteractionResult.PASS; } else { - BlockData vanillaBlockState = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()); - // 原版状态可燃烧,则跳过 - if (BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(vanillaBlockState))) { + // 点击对象为自定义方块 + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + // 原版外观也可燃 + if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) { return InteractionResult.PASS; } - - // 客户端一定觉得这个东西不可燃烧 - BlockPos belowFirePos = firePos.relative(Direction.DOWN); - BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); - boolean belowCanBurn; - try { - Block belowBlock = belowFireBlock.block(); - belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || - (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( - BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); - return InteractionResult.PASS; - } - - // 客户端觉得这玩意可交互,就会忽略声音 - if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { - // 如果按住了shift,则不会挥手,补发 - if (player.isSecondaryUseActive()) { - // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 - if (!belowCanBurn) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - player.swingHand(context.getHand()); - } - } else { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()); + // 点击的是方块上面,则只需要判断shift和可交互 + if (context.getClickedFace() == Direction.UP) { + // 客户端层面必须可交互 + if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, + context.getHitResult(), (Item) context.getItem())) { + return InteractionResult.PASS; + } + // 且没有shift + if (!player.isSecondaryUseActive()) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); } } else { - if (!belowCanBurn) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - player.swingHand(context.getHand()); + // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 + BlockPos belowFirePos = firePos.relative(Direction.DOWN); + BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); + boolean belowCanBurn; + try { + Block belowBlock = belowFireBlock.block(); + belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || + (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + + // 客户端觉得这玩意可交互,就会忽略声音 + if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { + // 如果按住了shift,则代表尝试对侧面方块点火 + if (player.isSecondaryUseActive()) { + // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } else { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + // 如果底部方块不可燃烧才补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } } } } + } else { + // 如果点击的方块不可燃烧,但是服务端却认为可以放置火源,则可燃烧的方块一定位于火源的六个方向之一。 + Direction relativeDirection = direction.opposite(); + for (Direction dir : Direction.values()) { + if (dir == relativeDirection) continue; + BlockPos relPos = firePos.relative(dir); + BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos); + BlockData nearbyBlockData = nearByBlock.block().getBlockData(); + Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData); + int stateID = BlockStateUtils.blockStateToId(nearbyBlockState); + if (BlockStateUtils.isVanillaBlock(stateID)) { + if (BlockStateUtils.isBurnable(nearbyBlockState)) { + return InteractionResult.PASS; + } + } + } + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); } return InteractionResult.PASS; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 16c8c2bfb..8adcef88f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -35,6 +35,7 @@ import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; import org.bukkit.*; @@ -288,6 +289,11 @@ public class BukkitServerPlayer extends Player { platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } + @Override + public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); + } + @Override public void giveItem(Item item) { PlayerUtils.giveItem(platformPlayer(), (ItemStack) item.getItem(), item.count()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 302d40d78..75b10c4f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -88,6 +89,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void playSound(Key sound, SoundSource source, float volume, float pitch); + public abstract void playSound(Key sound, BlockPos pos, SoundSource source, float volume, float pitch); + public abstract void giveItem(Item item); public abstract void closeInventory();