diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 0a6cf5176..8da86d668 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -97,7 +97,7 @@ public final class BlockEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerBreak(BlockBreakEvent event) { org.bukkit.block.Block block = event.getBlock(); Object blockState = BlockStateUtils.getBlockState(block); @@ -109,7 +109,7 @@ public final class BlockEventListener implements Listener { WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - if (!ItemUtils.isEmpty(itemInHand)) { + if (!event.isCancelled() && !ItemUtils.isEmpty(itemInHand)) { Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isPresent()) { Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); @@ -129,41 +129,49 @@ public final class BlockEventListener implements Listener { } if (!BlockStateUtils.isVanillaBlock(stateId)) { - ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId); + ImmutableBlockState state = this.manager.getImmutableBlockStateUnsafe(stateId); if (!state.isEmpty()) { - // double check adventure mode to prevent dupe - if (!FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) { - return; - } + if (!event.isCancelled()) { + // double check adventure mode to prevent dupe + if (!FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) { + return; + } - // trigger api event - CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(serverPlayer, location, block, state); - boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent); - if (isCancelled) { - event.setCancelled(true); - return; - } + // trigger api event + CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(serverPlayer, location, block, state); + boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent); + if (isCancelled) { + event.setCancelled(true); + return; + } - // execute functions - Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block)) - .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.POSITION, position) - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand) - ); - state.owner().value().execute(context, EventTrigger.BREAK); - if (cancellable.isCancelled()) { - return; - } + // execute functions + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block)) + .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, position) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand) + ); + state.owner().value().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + return; + } - // play sound - serverPlayer.playSound(position, state.settings().sounds().breakSound(), SoundSource.BLOCK); + // play sound + serverPlayer.playSound(position, state.settings().sounds().breakSound(), SoundSource.BLOCK); + } + // Restore sounds in cancelled events + else { + if (Config.processCancelledBreak()) { + serverPlayer.playSound(position, state.settings().sounds().breakSound(), SoundSource.BLOCK); + } + } } } else { // override vanilla block loots - if (player.getGameMode() != GameMode.CREATIVE) { + if (!event.isCancelled() && player.getGameMode() != GameMode.CREATIVE) { this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> { if (!event.isDropItems()) { return; @@ -185,7 +193,7 @@ public final class BlockEventListener implements Listener { }); } // sound system - if (Config.enableSoundSystem()) { + if (Config.enableSoundSystem() && (!event.isCancelled() || Config.processCancelledBreak())) { Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); @@ -223,7 +231,7 @@ public final class BlockEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) + @EventHandler(priority = EventPriority.LOW) public void onStep(GenericGameEvent event) { if (event.getEvent() != GameEvent.STEP) return; Entity entity = event.getEntity(); @@ -242,11 +250,14 @@ public final class BlockEventListener implements Listener { .withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block)) .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) ), EventTrigger.STEP); - if (cancellable.isCancelled()) { + if (cancellable.isCancelled() && !Config.processCancelledStep()) { return; } player.playSound(location, state.settings().sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.settings().sounds().stepSound().volume().get(), state.settings().sounds().stepSound().pitch().get()); } else if (Config.enableSoundSystem()) { + if (event.isCancelled() && !Config.processCancelledStep()) { + return; + } Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); Object soundEvent = FastNMS.INSTANCE.field$SoundType$stepSound(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 139001e20..bd8b101a0 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -261,6 +261,10 @@ block: # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: enable: true + # Should we process events that were canceled by other plugins to restore sounds? + process-cancelled-events: + step: true + break: true # Adventure mode requires correct tools to break custom blocks. # Vanilla clients cannot recognize custom block IDs (e.g., craftengine:custom_100). # diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 76ff553a7..c75eaa370 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -138,6 +138,8 @@ public class Config { protected ColliderType furniture$collision_entity_type; protected boolean block$sound_system$enable; + protected boolean block$sound_system$process_cancelled_events$step; + protected boolean block$sound_system$process_cancelled_events$break; protected boolean block$simplify_adventure_break_check; protected boolean block$simplify_adventure_place_check; protected boolean block$predict_breaking; @@ -475,6 +477,8 @@ public class Config { // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); + block$sound_system$process_cancelled_events$step = config.getBoolean("block.sound-system.process-cancelled-events.step", true); + block$sound_system$process_cancelled_events$break = config.getBoolean("block.sound-system.process-cancelled-events.break", true); block$simplify_adventure_break_check = config.getBoolean("block.simplify-adventure-break-check", false); block$simplify_adventure_place_check = config.getBoolean("block.simplify-adventure-place-check", false); block$predict_breaking = config.getBoolean("block.predict-breaking.enable", true); @@ -675,6 +679,14 @@ public class Config { return instance.block$sound_system$enable; } + public static boolean processCancelledStep() { + return instance.block$sound_system$process_cancelled_events$step; + } + + public static boolean processCancelledBreak() { + return instance.block$sound_system$process_cancelled_events$break; + } + public static boolean simplifyAdventureBreakCheck() { return instance.block$simplify_adventure_break_check; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java index 8cc171076..146807f4d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java @@ -5,6 +5,8 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.ArrayUtils; +import net.momirealms.craftengine.core.util.EnumUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -42,7 +44,7 @@ public class HandCondition implements Condition { try { return new HandCondition<>(InteractionHand.valueOf(hand.toUpperCase(Locale.ENGLISH))); } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.condition.hand.invalid_hand", hand); + throw new LocalizedResourceConfigException("warning.config.condition.hand.invalid_hand", hand, EnumUtils.toString(InteractionHand.values())); } } }