diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FacingTriggerableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FacingTriggerableBlockBehavior.java index b4a9ba41b..df3a1d8e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FacingTriggerableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FacingTriggerableBlockBehavior.java @@ -9,17 +9,42 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import java.util.List; +import java.util.Optional; import java.util.concurrent.Callable; public abstract class FacingTriggerableBlockBehavior extends BukkitBlockBehavior { + protected static final List DEFAULT_BLACKLIST_BLOCKS = List.of( + Key.of("minecraft:bedrock"), + Key.of("minecraft:end_portal_frame"), + Key.of("minecraft:end_portal"), + Key.of("minecraft:nether_portal"), + Key.of("minecraft:barrier"), + Key.of("minecraft:command_block"), + Key.of("minecraft:chain_command_block"), + Key.of("minecraft:repeating_command_block"), + Key.of("minecraft:structure_block"), + Key.of("minecraft:end_gateway"), + Key.of("minecraft:jigsaw"), + Key.of("minecraft:structure_void"), + Key.of("minecraft:test_instance_block"), + Key.of("minecraft:moving_piston"), + Key.of("minecraft:test_block"), + Key.of("minecraft:light") + ); protected final Property facingProperty; protected final Property triggeredProperty; + protected final List blocks; + protected final boolean whitelistMode; - public FacingTriggerableBlockBehavior(CustomBlock customBlock, Property facing, Property triggered) { + public FacingTriggerableBlockBehavior(CustomBlock customBlock, Property facing, Property triggered, List blocks, boolean whitelistMode) { super(customBlock); this.facingProperty = facing; this.triggeredProperty = triggered; + this.blocks = blocks; + this.whitelistMode = whitelistMode; } @Override @@ -50,6 +75,17 @@ public abstract class FacingTriggerableBlockBehavior extends BukkitBlockBehavior return state.owner().value().defaultState().with(this.facingProperty, direction); } + protected boolean blockCheck(Object blockState) { + if (blockState == null || FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { + return false; + } + Key blockId = Optional.ofNullable(BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState))) + .filter(state -> !state.isEmpty()) + .map(state -> state.owner().value().id()) + .orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(blockState)); + return this.blocks.contains(blockId) == this.whitelistMode; + } + protected abstract Object getTickPriority(); protected abstract void tick(Object state, Object level, Object pos); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PickaxeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PickaxeBlockBehavior.java index 45d15eb7b..cc559a057 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PickaxeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PickaxeBlockBehavior.java @@ -17,36 +17,13 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.Callable; public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior { public static final Factory FACTORY = new Factory(); - private static final List DEFAULT_BLACK_BLOCKS = List.of( - Key.of("minecraft:bedrock"), - Key.of("minecraft:end_portal_frame"), - Key.of("minecraft:end_portal"), - Key.of("minecraft:nether_portal"), - Key.of("minecraft:barrier"), - Key.of("minecraft:command_block"), - Key.of("minecraft:chain_command_block"), - Key.of("minecraft:repeating_command_block"), - Key.of("minecraft:structure_block"), - Key.of("minecraft:end_gateway"), - Key.of("minecraft:jigsaw"), - Key.of("minecraft:structure_void"), - Key.of("minecraft:test_instance_block"), - Key.of("minecraft:moving_piston"), - Key.of("minecraft:test_block"), - Key.of("minecraft:light") - ); - private final List blocks; - private final boolean whitelistMode; public PickaxeBlockBehavior(CustomBlock customBlock, Property facing, Property triggered, List blocks, boolean whitelistMode) { - super(customBlock, facing, triggered); - this.blocks = blocks; - this.whitelistMode = whitelistMode; + super(customBlock, facing, triggered, blocks, whitelistMode); } @Override @@ -67,22 +44,11 @@ public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior { ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); if (blockState == null || blockState.isEmpty()) return; Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, DirectionUtils.toNMSDirection(blockState.get(this.facingProperty))); - if (breakCheck(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) { + if (blockCheck(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) { FastNMS.INSTANCE.method$LevelWriter$destroyBlock(level, blockPos, true, null, 512); } } - private boolean breakCheck(Object blockState) { - if (blockState == null || FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { - return false; - } - Key blockId = Optional.ofNullable(BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState))) - .filter(state -> !state.isEmpty()) - .map(state -> state.owner().value().id()) - .orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(blockState)); - return this.blocks.contains(blockId) == this.whitelistMode; - } - public static class Factory implements BlockBehaviorFactory { @Override @@ -93,7 +59,7 @@ public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior { boolean whitelistMode = (boolean) arguments.getOrDefault("whitelist", false); List blocks = MiscUtils.getAsStringList(arguments.get("blocks")).stream().map(Key::of).toList(); if (blocks.isEmpty() && !whitelistMode) { - blocks = DEFAULT_BLACK_BLOCKS; + blocks = FacingTriggerableBlockBehavior.DEFAULT_BLACKLIST_BLOCKS; } return new PickaxeBlockBehavior(block, facing, triggered, blocks, whitelistMode); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PlaceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PlaceBlockBehavior.java index aa5c2d6da..95fc822a5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PlaceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PlaceBlockBehavior.java @@ -21,6 +21,8 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; @@ -38,8 +40,8 @@ import java.util.function.Function; public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior { public static final Factory FACTORY = new Factory(); - public PlaceBlockBehavior(CustomBlock customBlock, Property facing, Property triggered) { - super(customBlock, facing, triggered); + public PlaceBlockBehavior(CustomBlock customBlock, Property facing, Property triggered, List blocks, boolean whitelistMode) { + super(customBlock, facing, triggered, blocks, whitelistMode); } @Override @@ -69,17 +71,23 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior { return false; } else { Object itemStack1 = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack); - boolean flag = CoreReflections.clazz$BlockItem.isInstance(itemStack1) - && FastNMS.INSTANCE.method$InteractionResult$consumesAction(FastNMS.INSTANCE.method$BlockItem$place( - itemStack1, FastNMS.INSTANCE.constructor$PlaceBlockBlockPlaceContext( - level, CoreReflections.instance$InteractionHand$MAIN_HAND, itemStack, - FastNMS.INSTANCE.constructor$BlockHitResult( - FastNMS.INSTANCE.method$BlockPos$getCenter(LocationUtils.toBlockPos(blockPos1)), - DirectionUtils.toNMSDirection(opposite), - LocationUtils.toBlockPos(blockPos1), - false - ) - ))); + boolean flag = false; + if (CoreReflections.clazz$BlockItem.isInstance(itemStack1)) { + Object block = FastNMS.INSTANCE.method$BlockItem$getBlock(itemStack1); + if (blockCheck(FastNMS.INSTANCE.method$Block$defaultState(block))) { + Object blockHitResult = FastNMS.INSTANCE.constructor$BlockHitResult( + FastNMS.INSTANCE.method$BlockPos$getCenter(LocationUtils.toBlockPos(blockPos1)), + DirectionUtils.toNMSDirection(opposite), + LocationUtils.toBlockPos(blockPos1), + false + ); + Object placeBlockBlockPlaceContext = FastNMS.INSTANCE.constructor$PlaceBlockBlockPlaceContext( + level, CoreReflections.instance$InteractionHand$MAIN_HAND, itemStack, blockHitResult + ); + Object interactionResult = FastNMS.INSTANCE.method$BlockItem$place(itemStack1, placeBlockBlockPlaceContext); + flag = FastNMS.INSTANCE.method$InteractionResult$consumesAction(interactionResult); + } + } if (!flag) { Item item = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); @@ -93,12 +101,19 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior { CraftEngine.instance().logger().warn("Failed to place unknown block " + blockItemBehavior.block()); continue; } + ImmutableBlockState placeBlockState = optionalBlock.get().defaultState(); + if (placeBlockState.contains(this.facingProperty)) { + placeBlockState = placeBlockState.with(this.facingProperty, opposite); + } + if (blockCheck(placeBlockState.customBlockState().handle())) { + continue; + } Location placeLocation = new Location(FastNMS.INSTANCE.method$Level$getCraftWorld(level), blockPos1.x(), blockPos1.y(), blockPos1.z()); if (placeLocation.getBlock().getType() != Material.AIR) { break; } // TODO: 修复放置多方块自定义方块问题 - if (CraftEngineBlocks.place(placeLocation, optionalBlock.get().defaultState(), UpdateOption.UPDATE_ALL_IMMEDIATE, true)) { + if (CraftEngineBlocks.place(placeLocation, placeBlockState, UpdateOption.UPDATE_ALL_IMMEDIATE, true)) { return true; } } @@ -211,7 +226,12 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Property facing = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.place_block.missing_facing"); Property triggered = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("triggered"), "warning.config.block.behavior.place_block.missing_triggered"); - return new PlaceBlockBehavior(block, facing, triggered); + boolean whitelistMode = (boolean) arguments.getOrDefault("whitelist", false); + List blocks = MiscUtils.getAsStringList(arguments.get("blocks")).stream().map(Key::of).toList(); + if (blocks.isEmpty() && !whitelistMode) { + blocks = FacingTriggerableBlockBehavior.DEFAULT_BLACKLIST_BLOCKS; + } + return new PlaceBlockBehavior(block, facing, triggered, blocks, whitelistMode); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 5e1be06ea..7e87edf34 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -92,8 +92,7 @@ public class ComponentItemWrapper implements ItemWrapper { } public void setJavaComponent(Object type, Object value) { - setSparrowNBTComponent(type, MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, value)); - // setComponentInternal(type, MRegistryOps.JAVA, value); // 这里可能出现潜在的Integer和Boolean不区分问题 + setComponentInternal(type, MRegistryOps.JAVA, value); } public void setJsonComponent(Object type, JsonElement value) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 21a2b347d..94bf052ad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -162,6 +162,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket); registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket); + registerNMSPacketConsumer(PacketConsumers.CLIENT_INFO, NetworkReflections.clazz$ServerboundClientInformationPacket); registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 4fa8930ef..b22fc72a3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -2414,4 +2414,23 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e); } }; + + public static final TriConsumer CLIENT_INFO = (user, event, packet) -> { + try { + Map information = FastNMS.INSTANCE.method$ServerboundClientInformationPacket$information(packet); + user.setClientInformation(new ClientInformation( + (String) information.getOrDefault("language", "en_us"), + (int) information.getOrDefault("viewDistance", 2), + information.getOrDefault("chatVisibility", null), + (boolean) information.getOrDefault("chatColors", true), + (int) information.getOrDefault("modelCustomisation", 0), + information.getOrDefault("mainHand", null), + (boolean) information.getOrDefault("textFilteringEnabled", false), + (boolean) information.getOrDefault("allowsListing", false), + information.getOrDefault("particleStatus", null) + )); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 40ffdc977..4acedf0be 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1089,20 +1089,12 @@ public final class NetworkReflections { ReflectionUtils.getDeclaredConstructor(clazz$ClientboundMoveEntityPacket$Pos, int.class, short.class, short.class, short.class, boolean.class) ); - // 1.20.2+ - public static final Class clazz$ServerboundClientInformationPacket = - ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundClientInformationPacket")); - - // 1.20.2+ - public static final Constructor constructor$ServerboundClientInformationPacket = Optional.ofNullable(clazz$ServerboundClientInformationPacket) - .map(it -> ReflectionUtils.getConstructor(it, 1)) - .orElse(null); - - // 1.20.2+ - public static final Field field$ServerboundClientInformationPacket$information = Optional.ofNullable(clazz$ServerboundClientInformationPacket) - .map(it -> ReflectionUtils.getDeclaredField(it, 0)) - .orElse(null); - + public static final Class clazz$ServerboundClientInformationPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + List.of("network.protocol.game.PacketPlayInSettings", "network.protocol.common.ServerboundClientInformationPacket"), + List.of("network.protocol.game.ServerboundClientInformationPacket", "network.protocol.common.ServerboundClientInformationPacket") + ) + ); public static final Class clazz$ClientboundSetTitleTextPacket = requireNonNull( ReflectionUtils.getClazz( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 3a25e446c..24d33abb9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; import net.momirealms.craftengine.core.sound.SoundSource; +import net.momirealms.craftengine.core.util.ClientInformation; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -75,6 +76,7 @@ public class BukkitServerPlayer extends Player { // client side dimension info private int sectionCount; private Key clientSideDimension; + private ClientInformation clientInformation; // check main hand/offhand interaction private int lastSuccessfulInteraction; // re-sync attribute timely to prevent some bugs @@ -884,6 +886,16 @@ public class BukkitServerPlayer extends Player { this.sentResourcePack = sentResourcePack; } + @Override + public void setClientInformation(ClientInformation clientInfo) { + this.clientInformation = clientInfo; + } + + @Override + public ClientInformation getClientInformation() { + return this.clientInformation; + } + @Override public void clearView() { this.entityTypeView.clear(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 2dc4f282a..35b582128 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -4,6 +4,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.Plugin; +import net.momirealms.craftengine.core.util.ClientInformation; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; @@ -64,4 +65,8 @@ public interface NetWorkUser { boolean sentResourcePack(); void setSentResourcePack(boolean sentResourcePack); + + void setClientInformation(ClientInformation clientInfo); + + ClientInformation getClientInformation(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ClientInformation.java b/core/src/main/java/net/momirealms/craftengine/core/util/ClientInformation.java new file mode 100644 index 000000000..6fbf561d4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ClientInformation.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.util; + +public record ClientInformation(String language, int viewDistance, Object chatVisibility, + boolean chatColors, int modelCustomisation, Object mainHand, + boolean textFilteringEnabled, boolean allowsListing, Object particleStatus) { +} diff --git a/gradle.properties b/gradle.properties index f7d0b6556..50a45b57d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,7 +51,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.67.36 +nms_helper_version=0.67.37 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23