9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge branch 'Xiao-MoMi:dev' into dev

This commit is contained in:
jhqwqmc
2025-11-18 19:38:46 +08:00
committed by GitHub
22 changed files with 230 additions and 54 deletions

View File

@@ -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) { public void onPlayerBreak(BlockBreakEvent event) {
org.bukkit.block.Block block = event.getBlock(); org.bukkit.block.Block block = event.getBlock();
Object blockState = BlockStateUtils.getBlockState(block); 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); WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5);
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
if (!ItemUtils.isEmpty(itemInHand)) { if (!event.isCancelled() && !ItemUtils.isEmpty(itemInHand)) {
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem(); Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
if (optionalCustomItem.isPresent()) { if (optionalCustomItem.isPresent()) {
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
@@ -129,8 +129,9 @@ public final class BlockEventListener implements Listener {
} }
if (!BlockStateUtils.isVanillaBlock(stateId)) { if (!BlockStateUtils.isVanillaBlock(stateId)) {
ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId); ImmutableBlockState state = this.manager.getImmutableBlockStateUnsafe(stateId);
if (!state.isEmpty()) { if (!state.isEmpty()) {
if (!event.isCancelled()) {
// double check adventure mode to prevent dupe // double check adventure mode to prevent dupe
if (!FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) { if (!FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) {
return; return;
@@ -161,9 +162,16 @@ public final class BlockEventListener implements Listener {
// play sound // play sound
serverPlayer.playSound(position, state.settings().sounds().breakSound(), SoundSource.BLOCK); 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 { } else {
// override vanilla block loots // override vanilla block loots
if (player.getGameMode() != GameMode.CREATIVE) { if (!event.isCancelled() && player.getGameMode() != GameMode.CREATIVE) {
this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> { this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> {
if (!event.isDropItems()) { if (!event.isDropItems()) {
return; return;
@@ -185,7 +193,7 @@ public final class BlockEventListener implements Listener {
}); });
} }
// sound system // sound system
if (Config.enableSoundSystem()) { if (Config.enableSoundSystem() && (!event.isCancelled() || Config.processCancelledBreak())) {
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); 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) { public void onStep(GenericGameEvent event) {
if (event.getEvent() != GameEvent.STEP) return; if (event.getEvent() != GameEvent.STEP) return;
Entity entity = event.getEntity(); Entity entity = event.getEntity();
@@ -242,11 +250,14 @@ public final class BlockEventListener implements Listener {
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block)) .withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state)
), EventTrigger.STEP); ), EventTrigger.STEP);
if (cancellable.isCancelled()) { if (cancellable.isCancelled() && !Config.processCancelledStep()) {
return; return;
} }
player.playSound(location, state.settings().sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.settings().sounds().stepSound().volume().get(), state.settings().sounds().stepSound().pitch().get()); 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()) { } else if (Config.enableSoundSystem()) {
if (event.isCancelled() && !Config.processCancelledStep()) {
return;
}
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$stepSound(soundType); Object soundEvent = FastNMS.INSTANCE.field$SoundType$stepSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.HorizontalDirection; import net.momirealms.craftengine.core.util.HorizontalDirection;
@@ -20,7 +21,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class AttachedStemBlockBehavior extends BukkitBlockBehavior { public class AttachedStemBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<HorizontalDirection> facingProperty; private final Property<HorizontalDirection> facingProperty;
private final Key fruit; private final Key fruit;

View File

@@ -15,6 +15,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.Property;
import net.momirealms.craftengine.core.block.properties.type.DoorHinge; import net.momirealms.craftengine.core.block.properties.type.DoorHinge;
import net.momirealms.craftengine.core.block.properties.type.DoubleBlockHalf; import net.momirealms.craftengine.core.block.properties.type.DoubleBlockHalf;
@@ -46,7 +47,7 @@ import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<DoubleBlockHalf> halfProperty; private final Property<DoubleBlockHalf> halfProperty;
private final Property<HorizontalDirection> facingProperty; private final Property<HorizontalDirection> facingProperty;

View File

@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.block.properties.BooleanProperty;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
@@ -30,7 +31,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class FenceBlockBehavior extends BukkitBlockBehavior { public class FenceBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final BooleanProperty northProperty; private final BooleanProperty northProperty;
private final BooleanProperty eastProperty; private final BooleanProperty eastProperty;

View File

@@ -12,6 +12,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
@@ -40,7 +41,7 @@ import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public class FenceGateBlockBehavior extends BukkitBlockBehavior { public class FenceGateBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<HorizontalDirection> facingProperty; private final Property<HorizontalDirection> facingProperty;
private final Property<Boolean> inWallProperty; private final Property<Boolean> inWallProperty;

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.Property;
import net.momirealms.craftengine.core.block.properties.type.SlabType; import net.momirealms.craftengine.core.block.properties.type.SlabType;
import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.CustomItem;
@@ -24,7 +25,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class SlabBlockBehavior extends BukkitBlockBehavior { public class SlabBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<SlabType> typeProperty; private final Property<SlabType> typeProperty;

View File

@@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
@@ -21,7 +22,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class StemBlockBehavior extends BukkitBlockBehavior { public class StemBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final IntegerProperty ageProperty; private final IntegerProperty ageProperty;
private final Key fruit; private final Key fruit;

View File

@@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.Property;
import net.momirealms.craftengine.core.block.properties.type.SingleBlockHalf; import net.momirealms.craftengine.core.block.properties.type.SingleBlockHalf;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
@@ -40,7 +41,7 @@ import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public class TrapDoorBlockBehavior extends BukkitBlockBehavior { public class TrapDoorBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<SingleBlockHalf> halfProperty; private final Property<SingleBlockHalf> halfProperty;
private final Property<HorizontalDirection> facingProperty; private final Property<HorizontalDirection> facingProperty;

View File

@@ -2,10 +2,7 @@ package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.*;
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.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -18,7 +15,7 @@ import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
implements FallOnBlockBehavior, PlaceLiquidBlockBehavior { implements FallOnBlockBehavior, PlaceLiquidBlockBehavior, IsPathFindableBlockBehavior {
private final AbstractBlockBehavior[] behaviors; private final AbstractBlockBehavior[] behaviors;
public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List<AbstractBlockBehavior> behaviors) { public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List<AbstractBlockBehavior> behaviors) {
@@ -237,12 +234,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
@Override @Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception { public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
boolean processed = false;
for (AbstractBlockBehavior behavior : this.behaviors) { for (AbstractBlockBehavior behavior : this.behaviors) {
if (!behavior.isPathFindable(thisBlock, args, superMethod)) { if (behavior instanceof IsPathFindableBlockBehavior pathFindableBlockBehavior) {
if (!pathFindableBlockBehavior.isPathFindable(thisBlock, args, superMethod)) {
return false; return false;
} else {
processed = true;
} }
} }
return (boolean) superMethod.call(); }
if (!processed) return (boolean) superMethod.call();
return true;
} }
@Override @Override

View File

@@ -33,6 +33,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new ReloadCommand(this, plugin), new ReloadCommand(this, plugin),
new GetItemCommand(this, plugin), new GetItemCommand(this, plugin),
new GiveItemCommand(this, plugin), new GiveItemCommand(this, plugin),
new ClearItemCommand(this, plugin),
new ItemBrowserPlayerCommand(this, plugin), new ItemBrowserPlayerCommand(this, plugin),
new ItemBrowserAdminCommand(this, plugin), new ItemBrowserAdminCommand(this, plugin),
new SearchRecipePlayerCommand(this, plugin), new SearchRecipePlayerCommand(this, plugin),

View File

@@ -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<CommandSender> {
public ClearItemCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.flag(FlagKeys.SILENT_FLAG)
.required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true))
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> 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<Object> predicate = nmsStack -> {
Optional<Key> id = BukkitItemManager.instance().wrap(ItemStackUtils.asCraftMirror(nmsStack)).customId();
return id.isPresent() && id.get().equals(itemId);
};
int totalCount = 0;
Collection<Player> 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";
}
}

View File

@@ -51,4 +51,8 @@ public final class ItemStackUtils {
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack); Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
return UniqueIdItem.of(wrappedItem); return UniqueIdItem.of(wrappedItem);
} }
public static ItemStack asCraftMirror(Object itemStack) {
return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack);
}
} }

View File

@@ -43,6 +43,13 @@ give_item:
- /craftengine item give - /craftengine item give
- /ce 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: item_browser_player:
enable: true enable: true
permission: ce.command.player.item_browser permission: ce.command.player.item_browser

View File

@@ -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. # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience.
sound-system: sound-system:
enable: true 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. # Adventure mode requires correct tools to break custom blocks.
# Vanilla clients cannot recognize custom block IDs (e.g., craftengine:custom_100). # Vanilla clients cannot recognize custom block IDs (e.g., craftengine:custom_100).
# #

View File

@@ -49,6 +49,12 @@ command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>" command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>" command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>" command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.clear.failed.single: "<red><lang:clear.failed.single:'<arg:0>'></red>"
command.item.clear.failed.multiple: "<red><lang:clear.failed.multiple:'<arg:0>'></red>"
command.item.clear.success.single: "<lang:commands.clear.success.single:'<arg:0>':'<arg:1>'>"
command.item.clear.success.multiple: "<lang:commands.clear.success.multiple:'<arg:0>':'<arg:1>'>"
command.item.clear.test.single: "<lang:commands.clear.test.single:'<arg:0>':'<arg:1>'>"
command.item.clear.test.multiple: "<lang:commands.clear.test.multiple:'<arg:0>':'<arg:1>'>"
command.search_recipe.not_found: "<red>No recipe found for this item</red>" command.search_recipe.not_found: "<red>No recipe found for this item</red>"
command.search_usage.not_found: "<red>No usage found for this item</red>" command.search_usage.not_found: "<red>No usage found for this item</red>"
command.search_recipe.no_item: "<red>Please hold an item before running this command</red>" command.search_recipe.no_item: "<red>Please hold an item before running this command</red>"

View File

@@ -49,6 +49,12 @@ command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>" command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>" command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>" command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.clear.failed.single: "<red><lang:clear.failed.single:'<arg:0>'></red>"
command.item.clear.failed.multiple: "<red><lang:clear.failed.multiple:'<arg:0>'></red>"
command.item.clear.success.single: "<lang:commands.clear.success.single:'<arg:0>':'<arg:1>'>"
command.item.clear.success.multiple: "<lang:commands.clear.success.multiple:'<arg:0>':'<arg:1>'>"
command.item.clear.test.single: "<lang:commands.clear.test.single:'<arg:0>':'<arg:1>'>"
command.item.clear.test.multiple: "<lang:commands.clear.test.multiple:'<arg:0>':'<arg:1>'>"
command.search_recipe.not_found: "<red>找不到此物品的配方</red>" command.search_recipe.not_found: "<red>找不到此物品的配方</red>"
command.search_usage.not_found: "<red>找不到此物品的用途</red>" command.search_usage.not_found: "<red>找不到此物品的用途</red>"
command.search_recipe.no_item: "<red>请手持物品后再执行此命令</red>" command.search_recipe.no_item: "<red>请手持物品后再执行此命令</red>"

View File

@@ -704,7 +704,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
@NotNull @NotNull
private Map<String, Property<?>> parseBlockProperties(Map<String, Object> propertiesSection) { private Map<String, Property<?>> parseBlockProperties(Map<String, Object> propertiesSection) {
Map<String, Property<?>> properties = new HashMap<>(); Map<String, Property<?>> properties = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : propertiesSection.entrySet()) { for (Map.Entry<String, Object> entry : propertiesSection.entrySet()) {
Property<?> property = Properties.fromMap(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey())); Property<?> property = Properties.fromMap(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()));
properties.put(entry.getKey(), property); properties.put(entry.getKey(), property);

View File

@@ -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<Object> superMethod) throws Exception;
}

View File

@@ -138,6 +138,8 @@ public class Config {
protected ColliderType furniture$collision_entity_type; protected ColliderType furniture$collision_entity_type;
protected boolean block$sound_system$enable; 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_break_check;
protected boolean block$simplify_adventure_place_check; protected boolean block$simplify_adventure_place_check;
protected boolean block$predict_breaking; protected boolean block$predict_breaking;
@@ -475,6 +477,8 @@ public class Config {
// block // block
block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); 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_break_check = config.getBoolean("block.simplify-adventure-break-check", false);
block$simplify_adventure_place_check = config.getBoolean("block.simplify-adventure-place-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); block$predict_breaking = config.getBoolean("block.predict-breaking.enable", true);
@@ -675,6 +679,14 @@ public class Config {
return instance.block$sound_system$enable; 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() { public static boolean simplifyAdventureBreakCheck() {
return instance.block$simplify_adventure_break_check; return instance.block$simplify_adventure_break_check;
} }

View File

@@ -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.Context;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; 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.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
@@ -42,7 +43,7 @@ public class HandCondition<CTX extends Context> implements Condition<CTX> {
try { try {
return new HandCondition<>(InteractionHand.valueOf(hand.toUpperCase(Locale.ENGLISH))); return new HandCondition<>(InteractionHand.valueOf(hand.toUpperCase(Locale.ENGLISH)));
} catch (IllegalArgumentException e) { } 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()));
} }
} }
} }

View File

@@ -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_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_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_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");
} }

View File

@@ -1,9 +1,9 @@
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx1G
# Project settings # Project settings
project_version=0.0.65.8 project_version=0.0.65.9
config_version=55 config_version=56
lang_version=38 lang_version=39
project_group=net.momirealms project_group=net.momirealms
latest_supported_version=1.21.10 latest_supported_version=1.21.10
@@ -48,7 +48,7 @@ byte_buddy_version=1.17.8
ahocorasick_version=0.6.3 ahocorasick_version=0.6.3
snake_yaml_version=2.5 snake_yaml_version=2.5
anti_grief_version=1.0.4 anti_grief_version=1.0.4
nms_helper_version=1.0.134 nms_helper_version=1.0.135
evalex_version=3.5.0 evalex_version=3.5.0
reactive_streams_version=1.0.4 reactive_streams_version=1.0.4
amazon_awssdk_version=2.34.5 amazon_awssdk_version=2.34.5