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/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java index f35d35159..a156a4f61 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.HorizontalDirection; @@ -20,7 +21,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -public class AttachedStemBlockBehavior extends BukkitBlockBehavior { +public class AttachedStemBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property facingProperty; private final Key fruit; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java index 098092f9f..a93cdf0e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java @@ -15,6 +15,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.type.DoorHinge; import net.momirealms.craftengine.core.block.properties.type.DoubleBlockHalf; @@ -46,7 +47,7 @@ import java.util.Optional; import java.util.concurrent.Callable; @SuppressWarnings("DuplicatedCode") -public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { +public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property halfProperty; private final Property facingProperty; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java index 520c7b37d..bb84f9bd7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.BooleanProperty; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionResult; @@ -30,7 +31,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -public class FenceBlockBehavior extends BukkitBlockBehavior { +public class FenceBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final BooleanProperty northProperty; private final BooleanProperty eastProperty; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java index 03f0d1a11..64c86a1ca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; @@ -40,7 +41,7 @@ import java.util.Optional; import java.util.concurrent.Callable; @SuppressWarnings("DuplicatedCode") -public class FenceGateBlockBehavior extends BukkitBlockBehavior { +public class FenceGateBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property facingProperty; private final Property inWallProperty; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java index cf3137dd0..732aeb27e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.type.SlabType; import net.momirealms.craftengine.core.item.CustomItem; @@ -24,7 +25,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -public class SlabBlockBehavior extends BukkitBlockBehavior { +public class SlabBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property typeProperty; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java index 69755b7ac..452528c54 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.*; @@ -21,7 +22,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -public class StemBlockBehavior extends BukkitBlockBehavior { +public class StemBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final IntegerProperty ageProperty; private final Key fruit; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java index e945d546c..7d2793e02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.IsPathFindableBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.type.SingleBlockHalf; import net.momirealms.craftengine.core.entity.player.InteractionResult; @@ -40,7 +41,7 @@ import java.util.Optional; import java.util.concurrent.Callable; @SuppressWarnings("DuplicatedCode") -public class TrapDoorBlockBehavior extends BukkitBlockBehavior { +public class TrapDoorBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property halfProperty; private final Property facingProperty; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index c487b4ab1..3ddde1aa7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -2,10 +2,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.FallOnBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.PlaceLiquidBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.*; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; @@ -18,7 +15,7 @@ import java.util.Optional; import java.util.concurrent.Callable; public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior - implements FallOnBlockBehavior, PlaceLiquidBlockBehavior { + implements FallOnBlockBehavior, PlaceLiquidBlockBehavior, IsPathFindableBlockBehavior { private final AbstractBlockBehavior[] behaviors; public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List behaviors) { @@ -237,12 +234,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior @Override public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + boolean processed = false; for (AbstractBlockBehavior behavior : this.behaviors) { - if (!behavior.isPathFindable(thisBlock, args, superMethod)) { - return false; + if (behavior instanceof IsPathFindableBlockBehavior pathFindableBlockBehavior) { + if (!pathFindableBlockBehavior.isPathFindable(thisBlock, args, superMethod)) { + return false; + } else { + processed = true; + } } } - return (boolean) superMethod.call(); + if (!processed) return (boolean) superMethod.call(); + return true; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index 27dbb0857..82f859183 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -33,6 +33,7 @@ public class BukkitCommandManager extends AbstractCommandManager new ReloadCommand(this, plugin), new GetItemCommand(this, plugin), new GiveItemCommand(this, plugin), + new ClearItemCommand(this, plugin), new ItemBrowserPlayerCommand(this, plugin), new ItemBrowserAdminCommand(this, plugin), new SearchRecipePlayerCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ClearItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ClearItemCommand.java new file mode 100644 index 000000000..c387f4adf --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ClearItemCommand.java @@ -0,0 +1,98 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.command.FlagKeys; +import net.momirealms.craftengine.core.plugin.locale.MessageConstants; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.data.MultiplePlayerSelector; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.Collection; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + +public class ClearItemCommand extends BukkitCommandFeature { + + public ClearItemCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .flag(FlagKeys.SILENT_FLAG) + .required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true)) + .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); + } + })) + .optional("amount", IntegerParser.integerParser(0)) + .handler(context -> { + MultiplePlayerSelector selector = context.get("player"); + int amount = context.getOrDefault("amount", -1); + NamespacedKey namespacedKey = context.get("id"); + Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); + Predicate predicate = nmsStack -> { + Optional id = BukkitItemManager.instance().wrap(ItemStackUtils.asCraftMirror(nmsStack)).customId(); + return id.isPresent() && id.get().equals(itemId); + }; + int totalCount = 0; + Collection players = selector.values(); + for (Player player : players) { + Object serverPlayer = FastNMS.INSTANCE.method$CraftPlayer$getHandle(player); + Object inventory = FastNMS.INSTANCE.method$Player$getInventory(serverPlayer); + Object inventoryMenu = FastNMS.INSTANCE.field$Player$inventoryMenu(serverPlayer); + totalCount += FastNMS.INSTANCE.method$Inventory$clearOrCountMatchingItems(inventory, predicate, amount, FastNMS.INSTANCE.method$InventoryMenu$getCraftSlots(inventoryMenu)); + FastNMS.INSTANCE.method$AbstractContainerMenu$broadcastChanges(FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer)); + FastNMS.INSTANCE.method$InventoryMenu$slotsChanged(inventoryMenu, inventory); + } + if (totalCount == 0) { + if (players.size() == 1) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_FAILED_SINGLE, Component.text(players.iterator().next().getName())); + } else { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_FAILED_MULTIPLE, Component.text(players.size())); + } + } else { + if (amount == 0) { + if (players.size() == 1) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_TEST_SINGLE, Component.text(totalCount), Component.text(players.iterator().next().getName())); + } else { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_TEST_MULTIPLE, Component.text(totalCount), Component.text(players.size())); + } + } else { + if (players.size() == 1) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_SUCCESS_SINGLE, Component.text(totalCount), Component.text(players.iterator().next().getName())); + } else { + handleFeedback(context, MessageConstants.COMMAND_ITEM_CLEAR_SUCCESS_MULTIPLE, Component.text(totalCount), Component.text(players.size())); + } + } + } + }); + } + + @Override + public String getFeatureID() { + return "clear_item"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java index bbebf2a97..2e6425910 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java @@ -51,4 +51,8 @@ public final class ItemStackUtils { Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); return UniqueIdItem.of(wrappedItem); } + + public static ItemStack asCraftMirror(Object itemStack) { + return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack); + } } diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index f2ca1e16b..cd3ca9688 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -43,6 +43,13 @@ give_item: - /craftengine item give - /ce item give +clear_item: + enable: true + permission: ce.command.admin.clear_item + usage: + - /craftengine item clear + - /ce item clear + item_browser_player: enable: true permission: ce.command.player.item_browser 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/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 0594bda79..269e3d15b 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -49,6 +49,12 @@ command.item.get.failure.not_exist: "':'':''>" command.item.give.success.multiple: "':'':''>" command.item.give.failure.not_exist: "'>" +command.item.clear.failed.single: "'>" +command.item.clear.failed.multiple: "'>" +command.item.clear.success.single: "':''>" +command.item.clear.success.multiple: "':''>" +command.item.clear.test.single: "':''>" +command.item.clear.test.multiple: "':''>" command.search_recipe.not_found: "No recipe found for this item" command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 101473e72..b3d02de2b 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -49,6 +49,12 @@ command.item.get.failure.not_exist: "':'':''>" command.item.give.success.multiple: "':'':''>" command.item.give.failure.not_exist: "'>" +command.item.clear.failed.single: "'>" +command.item.clear.failed.multiple: "'>" +command.item.clear.success.single: "':''>" +command.item.clear.success.multiple: "':''>" +command.item.clear.test.single: "':''>" +command.item.clear.test.multiple: "':''>" command.search_recipe.not_found: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "请手持物品后再执行此命令" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index e9ff489b8..902f1fb82 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -704,7 +704,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem @NotNull private Map> parseBlockProperties(Map propertiesSection) { - Map> properties = new HashMap<>(); + Map> properties = new LinkedHashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { Property property = Properties.fromMap(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey())); properties.put(entry.getKey(), property); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/IsPathFindableBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/IsPathFindableBlockBehavior.java new file mode 100644 index 000000000..7fe7d8e06 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/IsPathFindableBlockBehavior.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.block.behavior; + +import java.util.concurrent.Callable; + +public interface IsPathFindableBlockBehavior { + + // 1.20-1.20.4 BlockState state, BlockGetter world, BlockPos pos, PathComputationType type + // 1.20.5+ BlockState state, PathComputationType pathComputationType + boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception; +} 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..eea93f8c8 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,7 @@ 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.EnumUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -42,7 +43,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())); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java index 882d17c90..b488bde08 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java @@ -35,4 +35,10 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_LOCALE_SET_FAILURE = Component.translatable().key("command.locale.set.failure"); TranslatableComponent.Builder COMMAND_LOCALE_SET_SUCCESS = Component.translatable().key("command.locale.set.success"); TranslatableComponent.Builder COMMAND_LOCALE_UNSET_SUCCESS = Component.translatable().key("command.locale.unset.success"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_SUCCESS_SINGLE = Component.translatable().key("command.item.clear.success.single"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_SUCCESS_MULTIPLE = Component.translatable().key("command.item.clear.success.multiple"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_FAILED_SINGLE = Component.translatable().key("command.item.clear.failed.single"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_FAILED_MULTIPLE = Component.translatable().key("command.item.clear.failed.multiple"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_TEST_SINGLE = Component.translatable().key("command.item.clear.test.single"); + TranslatableComponent.Builder COMMAND_ITEM_CLEAR_TEST_MULTIPLE = Component.translatable().key("command.item.clear.test.multiple"); } diff --git a/gradle.properties b/gradle.properties index ff17174fc..7e943f459 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings -project_version=0.0.65.8 -config_version=55 -lang_version=38 +project_version=0.0.65.9 +config_version=56 +lang_version=39 project_group=net.momirealms latest_supported_version=1.21.10 @@ -48,7 +48,7 @@ byte_buddy_version=1.17.8 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.4 -nms_helper_version=1.0.134 +nms_helper_version=1.0.135 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5