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) {
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<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
if (!ItemUtils.isEmpty(itemInHand)) {
if (!event.isCancelled() && !ItemUtils.isEmpty(itemInHand)) {
Optional<CustomItem<ItemStack>> 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);

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.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<HorizontalDirection> facingProperty;
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.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<DoubleBlockHalf> halfProperty;
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.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;

View File

@@ -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<HorizontalDirection> facingProperty;
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.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<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.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;

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.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<SingleBlockHalf> halfProperty;
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.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<AbstractBlockBehavior> behaviors) {
@@ -237,12 +234,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> 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

View File

@@ -33,6 +33,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
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),

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);
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
- /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

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.
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).
#

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.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.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_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>"

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.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.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_usage.not_found: "<red>找不到此物品的用途</red>"
command.search_recipe.no_item: "<red>请手持物品后再执行此命令</red>"

View File

@@ -704,7 +704,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
@NotNull
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()) {
Property<?> property = Properties.fromMap(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()));
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 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;
}

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.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<CTX extends Context> implements Condition<CTX> {
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()));
}
}
}

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

View File

@@ -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