diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index a8d5c862d..161171c20 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,23 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.entity.data.HappyGhastData; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.Command; -import org.incendo.cloud.bukkit.parser.location.LocationParser; -import org.incendo.cloud.parser.standard.IntegerParser; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; public class TestCommand extends BukkitCommandFeature { @@ -29,35 +18,9 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("location", LocationParser.locationParser()) - .required("remove", IntegerParser.integerParser()) .handler(context -> { Player player = context.sender(); - int removeEntityId = context.get("remove"); - if (removeEntityId >= 0) { - try { - Object packet = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{removeEntityId}); - plugin().adapt(player).sendPacket(packet, true); - player.sendMessage("发送成功"); - } catch (ReflectiveOperationException e) { - player.sendMessage("发送失败"); - } - return; - } - Location location = context.get("location"); - int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); - List packets = new ArrayList<>(); - List cachedShulkerValues = new ArrayList<>(); - HappyGhastData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, cachedShulkerValues); // NO AI - // HappyGhastData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, cachedShulkerValues); // Invisible - HappyGhastData.StaysStill.addEntityDataIfNotDefaultValue(true, cachedShulkerValues); - packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId, UUID.randomUUID(), location.x(), location.y(), location.z(), 0, location.getYaw(), - MEntityTypes.HAPPY_GHAST, 0, CoreReflections.instance$Vec3$Zero, 0 - )); - packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, List.copyOf(cachedShulkerValues))); - plugin().adapt(player).sendPackets(packets, true); - player.sendMessage("发送成功 id: " + entityId); + player.sendMessage("客户端模组状态: " + BukkitNetworkManager.instance().getUser(player).clientModEnabled()); }); } 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 8233043b3..4a2ba84c7 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 @@ -29,6 +29,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; @@ -105,7 +106,7 @@ public class PacketConsumers { byte yHeadRot = buf.readByte(); int data = buf.readVarInt(); // Falling blocks - int remapped = remap(data); + int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data); if (remapped != data) { int xa = buf.readShort(); int ya = buf.readShort(); @@ -428,7 +429,7 @@ public class PacketConsumers { if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { return; } - int state = remap(before); + int state = user.clientModEnabled() ? remapMOD(before) : remap(before); if (state == before) { return; } @@ -450,7 +451,7 @@ public class PacketConsumers { BlockPos blockPos = buf.readBlockPos(); int state = buf.readInt(); boolean global = buf.readBoolean(); - int newState = remap(state); + int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); if (newState == state) { return; } @@ -1006,7 +1007,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1046,7 +1047,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1086,7 +1087,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1884,34 +1885,38 @@ public class PacketConsumers { public static final TriConsumer CUSTOM_PAYLOAD = (user, event, packet) -> { try { - if (!VersionHelper.isOrAbove1_20_5()) return; + if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { - Payload discardedPayload = DiscardedPayload.from(payload); - if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + clientPayload = DiscardedPayload.from(payload); + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$UnknownPayload.isInstance(payload)) { + clientPayload = UnknownPayload.from(payload); + } else { + return; + } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + return; + FriendlyByteBuf buf = clientPayload.toBuffer(); + NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); + if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { + int clientBlockRegistrySize = dataType.decode(buf); + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (clientBlockRegistrySize != serverBlockRegistrySize) { + user.kick(Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + )); return; - FriendlyByteBuf buf = discardedPayload.toBuffer(); - NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); - if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.decode(buf); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - user.kick(Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - )); - return; - } - user.setClientModState(true); - } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (!VersionHelper.isOrAbove1_20_2()) return; - if (dataType.decode(buf)) { - FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - bufPayload.writeEnumConstant(dataType); - dataType.encode(bufPayload, true); - user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); - } + } + user.setClientModState(true); + } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { + if (dataType.decode(buf)) { + FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); + bufPayload.writeEnumConstant(dataType); + dataType.encode(bufPayload, true); + user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } } catch (Throwable e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java new file mode 100644 index 000000000..4143eea27 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public record UnknownPayload(Key channel, ByteBuf rawPayload) implements Payload{ + + public static UnknownPayload from(Object payload) { + try { + Object id = NetworkReflections.field$UnknownPayload$id.get(payload); + ByteBuf data = (ByteBuf) NetworkReflections.field$UnknownPayload$data.get(payload); + Key channel = KeyUtils.resourceLocationToKey(id); + return new UnknownPayload(channel, data); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to create UnknownPayload", e); + return null; + } + } + + @Override + public FriendlyByteBuf toBuffer() { + return new FriendlyByteBuf(rawPayload); + } +} 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 6c1d427a9..6c11c869e 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 @@ -1248,7 +1248,9 @@ public final class NetworkReflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) + VersionHelper.isOrAbove1_20_2() + ? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload) + : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$FriendlyByteBuf) ); // 1.20.2+ @@ -1621,4 +1623,27 @@ public final class NetworkReflections { throw new ReflectionInitException("Failed to initialize HashedStack$STREAM_CODEC", e); } } + + // 1.20.2~1.20.4 + public static final Class clazz$UnknownPayload = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket$UnknownPayload") + ), + VersionHelper.isOrAbove1_20_2() && !VersionHelper.isOrAbove1_20_5() + ); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$id = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ResourceLocation, 0)) + .orElse(null); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) + .orElse(null); + + // 1.20.2~1.20.4 + public static final Constructor constructor$UnknownPayload = Optional.ofNullable(clazz$UnknownPayload) + .map(ReflectionUtils::getTheOnlyConstructor) + .orElse(null); } 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 74430caf7..5e78643a6 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 @@ -306,13 +306,20 @@ public class BukkitServerPlayer extends Player { public void sendCustomPayload(Key channel, byte[] data) { try { Object channelKey = KeyUtils.toResourceLocation(channel); - Object dataPayload; - if (DiscardedPayload.useNewMethod) { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + Object responsePacket; + if (VersionHelper.isOrAbove1_20_2()) { + Object dataPayload; + if (NetworkReflections.clazz$UnknownPayload != null) { + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } else if (DiscardedPayload.useNewMethod) { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + } else { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); } else { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelKey, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data))); } - Object responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); this.sendPacket(responsePacket, true); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to send custom payload to " + name(), e);