From 4ad031e9ca80f185dbafe55b0f7aaa9cd6708d9e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 5 Jul 2025 20:28:58 +0800 Subject: [PATCH] =?UTF-8?q?refactor(pack):=20=E9=87=8D=E6=9E=84=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8C=85=E5=88=86=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/pack/BukkitPackManager.java | 23 ---- .../plugin/network/BukkitNetworkManager.java | 2 +- .../plugin/network/PacketConsumers.java | 106 +++++++------- .../reflection/minecraft/CoreReflections.java | 130 ++++++++++++++++++ .../minecraft/NetworkReflections.java | 62 +++++++++ .../plugin/user/BukkitServerPlayer.java | 17 +-- .../bukkit/util/ResourcePackUtils.java | 40 ++++++ .../core/plugin/network/NetWorkUser.java | 9 +- 8 files changed, 294 insertions(+), 95 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index fb69e797d..7ae11cc4f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -5,13 +5,11 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.ResourcePackUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.impl.NoneHost; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.VersionHelper; @@ -25,11 +23,9 @@ import org.bukkit.event.player.PlayerJoinEvent; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.CompletableFuture; public class BukkitPackManager extends AbstractPackManager implements Listener { - public static final String FAKE_URL = "https://127.0.0.1:65536"; private final BukkitCraftEngine plugin; public BukkitPackManager(BukkitCraftEngine plugin) { @@ -58,25 +54,6 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { public void load() { if (ReloadCommand.RELOAD_PACK_FLAG || CraftEngine.instance().isInitializing()) { super.load(); - if (Config.sendPackOnJoin() && VersionHelper.isOrAbove1_20_2() && !(resourcePackHost() instanceof NoneHost)) { - this.modifyServerSettings(); - } - } - } - - public void modifyServerSettings() { - try { - Object settings = CoreReflections.field$DedicatedServer$settings.get(CoreReflections.method$MinecraftServer$getServer.invoke(null)); - Object properties = CoreReflections.field$DedicatedServerSettings$properties.get(settings); - Object info; - if (VersionHelper.isOrAbove1_20_3()) { - info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(new UUID(0, 0), FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); - } else { - info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); - } - CoreReflections.field$DedicatedServerProperties$serverResourcePackInfo.set(properties, Optional.of(info)); - } catch (Exception e) { - this.plugin.logger().warn("Failed to update resource pack settings", e); } } 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 357c89dc3..4701fca90 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 @@ -149,13 +149,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket); registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, NetworkReflections.clazz$ServerboundEditBookPacket); registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, NetworkReflections.clazz$ServerboundCustomPayloadPacket); - registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_PUSH, NetworkReflections.clazz$ClientboundResourcePackPushPacket); registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); 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.FINISH_CONFIGURATION, NetworkReflections.clazz$ClientboundFinishConfigurationPacket); 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 ad04ada15..2425a262d 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 @@ -21,7 +21,6 @@ import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManag import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; @@ -2285,39 +2284,6 @@ public class PacketConsumers { } }; - public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_20_2()) return; - // we should only handle fake urls - String url = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$url(packet); - if (!url.equals(BukkitPackManager.FAKE_URL)) { - return; - } - event.setCancelled(true); - UUID packUUID = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$uuid(packet); - ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); - host.requestResourcePackDownloadLink(user.uuid()).thenAccept(dataList -> { - if (dataList.isEmpty()) { - user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID)); - return; - } - for (ResourcePackDownloadData data : dataList) { - Object newPacket = ResourcePackUtils.createPacket(data.uuid(), data.url(), data.sha1()); - user.sendPacket(newPacket, true); - user.addResourcePackUUID(data.uuid()); - } - user.remainingConfigurationStagePacks().set(dataList.size()); - user.setServerSideRealPackUUID(packUUID); - }).exceptionally(throwable -> { - CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", throwable); - user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID)); - return null; - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", e); - } - }; - public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { try { if (!Config.sendPackOnJoin()) return; @@ -2333,10 +2299,7 @@ public class PacketConsumers { // 检查是否是拒绝 if (Config.kickOnDeclined()) { if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED) { - Object kickPacket = NetworkReflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"))); - user.sendPacket(kickPacket, true); - user.nettyChannel().disconnect(); + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); return; } } @@ -2344,24 +2307,17 @@ public class PacketConsumers { if (Config.kickOnFailedApply()) { if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD || (VersionHelper.isOrAbove1_20_3() && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$INVALID_URL)) { - Object kickPacket = NetworkReflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"))); - user.sendPacket(kickPacket, true); - user.nettyChannel().disconnect(); + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); return; } } - // 将对于1.20.3+,适当时间转义为正确的uuid - if (VersionHelper.isOrAbove1_20_3()) { - UUID realUUID = user.getServerSideRealPackUUID(); - if (realUUID != null && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) { - int remaining = user.remainingConfigurationStagePacks().decrementAndGet(); - if (remaining == 0) { - event.setCancelled(true); - user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(realUUID)); - user.setServerSideRealPackUUID(null); - } - } + // 绕过1.21.7新增的校验 + if (VersionHelper.isOrAbove1_21_7()) { + event.setCancelled(true); + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) return; + // 根据要求需要运行在主线程上 + CraftEngine.instance().scheduler().executeSync(() -> ResourcePackUtils.handleResourcePackResponse(packetListener, packet, action)); } } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e); @@ -2432,4 +2388,48 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e); } }; + + public static final TriConsumer FINISH_CONFIGURATION = (user, event, packet) -> { + try { + if (!VersionHelper.isOrAbove1_20_2() || !user.shouldProcessFinishConfiguration() || !Config.sendPackOnJoin()) return; + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) { + return; + } + + user.setShouldProcessFinishConfiguration(false); // 防止loop + event.setCancelled(true); + ResourcePackUtils.finishCurrentTask(packetListener, CoreReflections.instance$JoinWorldTask$TYPE); + if (VersionHelper.isOrAbove1_20_5()) { + // 1.20.5+开始会检查是否结束需要重新设置回去,不然不会发keepAlive包 + CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false); + } + + ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); + host.requestResourcePackDownloadLink(user.uuid()).thenAccept(dataList -> { + if (dataList.isEmpty()) { + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + Queue configurationTasks = ResourcePackUtils.getConfigurationTasks(packetListener); + if (configurationTasks == null) { // 以防万一获取失败 + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + for (ResourcePackDownloadData data : dataList) { + configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask( + ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1())) + ); + user.addResourcePackUUID(data.uuid()); + } + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + }).exceptionally(throwable -> { + CraftEngine.instance().logger().warn("Failed to handle ClientboundFinishConfigurationPacket", throwable); + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return null; + }); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundFinishConfigurationPacket", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 3e66af812..41844a1d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -9,6 +9,7 @@ import io.netty.channel.ChannelFuture; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -3634,4 +3635,133 @@ public final class CoreReflections { ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, Map.class, clazz$Component) : ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, float.class, Map.class, clazz$Component) ); + + public static final Class clazz$ServerConfigurationPacketListenerImpl = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.ServerConfigurationPacketListenerImpl") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$ServerConfigurationPacketListenerImpl$configurationTasks = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl) + .map(it -> ReflectionUtils.getDeclaredField(it, Queue.class, 0)) + .orElse(null); + + public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter = + ReflectionUtils.unreflectGetter(field$ServerConfigurationPacketListenerImpl$configurationTasks) + .asType(MethodType.methodType(Queue.class, Object.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter = null; + } + } catch (IllegalAccessException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + public static final Class clazz$JoinWorldTask = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.config.JoinWorldTask") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Constructor constructor$JoinWorldTask = Optional.ofNullable(clazz$JoinWorldTask) + .map(ReflectionUtils::getTheOnlyConstructor) + .orElse(null); + + public static final Class clazz$ConfigurationTask$Type = MiscUtils.requireNonNullIf( + BukkitReflectionUtils.findReobfOrMojmapClass( + "server.network.ConfigurationTask$a", + "server.network.ConfigurationTask$Type" + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$JoinWorldTask$TYPE = Optional.ofNullable(clazz$JoinWorldTask) + .map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0)) + .orElse(null); + + public static final Class clazz$ServerResourcePackConfigurationTask = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.config.ServerResourcePackConfigurationTask") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$ServerResourcePackConfigurationTask$TYPE = Optional.ofNullable(clazz$ServerResourcePackConfigurationTask) + .map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0)) + .orElse(null); + + public static final Object instance$JoinWorldTask; + public static final Object instance$JoinWorldTask$TYPE; + public static final Object instance$ServerResourcePackConfigurationTask$TYPE; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + instance$JoinWorldTask = constructor$JoinWorldTask.newInstance(); + instance$JoinWorldTask$TYPE = field$JoinWorldTask$TYPE.get(null); + instance$ServerResourcePackConfigurationTask$TYPE = field$ServerResourcePackConfigurationTask$TYPE.get(null); + } else { + instance$JoinWorldTask = null; + instance$JoinWorldTask$TYPE = null; + instance$ServerResourcePackConfigurationTask$TYPE = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + // 注释的这些说不定以后调试有用 + // public static final Class clazz$ConfigurationTask = MiscUtils.requireNonNullIf( + // ReflectionUtils.getClazz( + // BukkitReflectionUtils.assembleMCClass("server.network.ConfigurationTask") + // ), + // VersionHelper.isOrAbove1_20_2() + // ); + // + // public static final Field field$ServerConfigurationPacketListenerImpl$currentTask = MiscUtils.requireNonNullIf( + // ReflectionUtils.getDeclaredField(clazz$ServerConfigurationPacketListenerImpl, clazz$ConfigurationTask, 0), + // VersionHelper.isOrAbove1_20_2() + // ); + + // 1.20.2+ + public static final Method method$ServerConfigurationPacketListenerImpl$finishCurrentTask = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl) + .map(it -> ReflectionUtils.getDeclaredMethod(it, void.class, clazz$ConfigurationTask$Type)) + .orElse( null); + + public static final Field field$ServerCommonPacketListenerImpl$closed = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredField(clazz$ServerCommonPacketListenerImpl, boolean.class, VersionHelper.isOrAbove1_21_6() ? 1 : 2), + VersionHelper.isOrAbove1_20_5() + ); + + public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask; + public static final MethodHandle methodHandle$ServerCommonPacketListenerImpl$closedSetter; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = + ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + methodHandle$ServerCommonPacketListenerImpl$closedSetter = + ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed) + .asType(MethodType.methodType(void.class, Object.class, boolean.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; + methodHandle$ServerCommonPacketListenerImpl$closedSetter = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize reflection", 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 6fa2b56b6..3992dfba5 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import io.netty.buffer.ByteBuf; import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -1492,4 +1493,65 @@ public final class NetworkReflections { throw new ReflectionInitException("Failed to initialize ParticleTypes$STREAM_CODEC", e); } } + + public static final Class clazz$ClientboundFinishConfigurationPacket = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.configuration.ClientboundFinishConfigurationPacket") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Constructor constructor$ClientboundFinishConfigurationPacket = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket) + .map(ReflectionUtils::getConstructor) + .orElse(null); + + // 1.20.5+ + public static final Field field$ClientboundFinishConfigurationPacket$INSTANCE = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket) + .map(it -> ReflectionUtils.getDeclaredField(it, it, 0)) + .orElse(null); + + public static final Object instance$ClientboundFinishConfigurationPacket$INSTANCE; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + instance$ClientboundFinishConfigurationPacket$INSTANCE = VersionHelper.isOrAbove1_20_5() + ? field$ClientboundFinishConfigurationPacket$INSTANCE.get(null) + : constructor$ClientboundFinishConfigurationPacket.newInstance(); + } else { + instance$ClientboundFinishConfigurationPacket$INSTANCE = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ClientboundFinishConfigurationPacket$INSTANCE", e); + } + } + + public static final Class clazz$ServerCommonPacketListener = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerCommonPacketListener") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Method method$ServerCommonPacketListener$handleResourcePackResponse = Optional.ofNullable(clazz$ServerCommonPacketListener) + .map(it -> ReflectionUtils.getMethod(it, void.class, clazz$ServerboundResourcePackPacket)) + .orElse(null); + + public static final MethodHandle methodHandle$ServerCommonPacketListener$handleResourcePackResponse; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerCommonPacketListener$handleResourcePackResponse = + ReflectionUtils.unreflectMethod(method$ServerCommonPacketListener$handleResourcePackResponse) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ServerCommonPacketListener$handleResourcePackResponse = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ServerCommonPacketListener$handleResourcePackResponse", e); + } + } } 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 a9dbd485e..3216a3bd1 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 @@ -54,7 +54,6 @@ import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; public class BukkitServerPlayer extends Player { private final BukkitCraftEngine plugin; @@ -66,8 +65,8 @@ public class BukkitServerPlayer extends Player { private UUID uuid; private ConnectionState decoderState; private ConnectionState encoderState; + private boolean shouldProcessFinishConfiguration = true; private final Set resourcePackUUID = Collections.synchronizedSet(new HashSet<>()); - private final AtomicInteger remainingConfigurationStagePacks = new AtomicInteger(0); // some references private Reference playerRef; private Reference serverPlayerRef; @@ -107,7 +106,6 @@ public class BukkitServerPlayer extends Player { private double cachedInteractionRange; // cooldown data private CooldownData cooldownData; - private UUID serverSideRealPackUUID; private final Map entityTypeView = new ConcurrentHashMap<>(); @@ -879,18 +877,13 @@ public class BukkitServerPlayer extends Player { } @Override - public AtomicInteger remainingConfigurationStagePacks() { - return this.remainingConfigurationStagePacks; + public void setShouldProcessFinishConfiguration(boolean shouldProcess) { + this.shouldProcessFinishConfiguration = shouldProcess; } @Override - public void setServerSideRealPackUUID(UUID uuid) { - this.serverSideRealPackUUID = uuid; - } - - @Override - public UUID getServerSideRealPackUUID() { - return this.serverSideRealPackUUID; + public boolean shouldProcessFinishConfiguration() { + return this.shouldProcessFinishConfiguration; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java index 757ca2414..37a93ca85 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java @@ -1,8 +1,13 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; +import org.jetbrains.annotations.Nullable; +import java.util.Queue; import java.util.UUID; public final class ResourcePackUtils { @@ -11,4 +16,39 @@ public final class ResourcePackUtils { public static Object createPacket(UUID uuid, String url, String hash) { return FastNMS.INSTANCE.constructor$ClientboundResourcePackPushPacket(uuid, url, hash, Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); } + + public static Object createServerResourcePackInfo(UUID uuid, String url, String hash) { + return FastNMS.INSTANCE.constructor$ServerResourcePackInfo(uuid, url, hash, Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); + } + + public static void finishCurrentTask(Object packetListener, Object type) { + try { + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, type); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to finish current task", e); + } + } + + @SuppressWarnings("unchecked") + @Nullable + public static Queue getConfigurationTasks(Object packetListener) { + try { + return (Queue) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get configuration tasks", e); + return null; + } + } + + public static void handleResourcePackResponse(Object packetListener, Object packet, Object action) { + try { + NetworkReflections.methodHandle$ServerCommonPacketListener$handleResourcePackResponse.invokeExact(packetListener, packet); + if (action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$ACCEPTED + && action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$DOWNLOADED) { + ResourcePackUtils.finishCurrentTask(packetListener, CoreReflections.instance$ServerResourcePackConfigurationTask$TYPE); + } + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e); + } + } } 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 df669ad6b..9ff316fcf 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 @@ -9,7 +9,6 @@ import org.jetbrains.annotations.ApiStatus; import java.util.Map; import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; public interface NetWorkUser { boolean isOnline(); @@ -58,11 +57,9 @@ public interface NetWorkUser { void addResourcePackUUID(UUID uuid); - void setServerSideRealPackUUID(UUID uuid); - - UUID getServerSideRealPackUUID(); - boolean isResourcePackLoading(UUID uuid); - AtomicInteger remainingConfigurationStagePacks(); + void setShouldProcessFinishConfiguration(boolean shouldProcess); + + boolean shouldProcessFinishConfiguration(); }