diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt index 9761a57..078ba80 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt @@ -4,8 +4,10 @@ import com.charleskorn.kaml.PolymorphismStyle import com.charleskorn.kaml.SingleLineStringStyle import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.YamlConfiguration +import com.github.shynixn.mccoroutine.bukkit.launch import com.mineinabyss.geary.autoscan.autoscan import com.mineinabyss.geary.modules.geary +import com.mineinabyss.geary.papermc.datastore.decode import com.mineinabyss.idofront.config.ConfigFormats import com.mineinabyss.idofront.config.Format import com.mineinabyss.idofront.config.config @@ -13,21 +15,26 @@ import com.mineinabyss.idofront.di.DI import com.mineinabyss.idofront.messaging.observeLogger import com.mineinabyss.idofront.nms.PacketListener import com.mineinabyss.idofront.nms.interceptClientbound -import com.mineinabyss.idofront.nms.interceptServerbound +import com.mineinabyss.idofront.nms.nbt.getOfflinePDC import com.mineinabyss.idofront.plugin.listeners +import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.packy.components.PackyData import com.mineinabyss.packy.config.* import com.mineinabyss.packy.listener.PlayerListener import com.mineinabyss.packy.listener.TemplateLoadTriggers +import io.papermc.paper.adventure.PaperAdventure import kotlinx.coroutines.Job import kotlinx.serialization.modules.EmptySerializersModule import net.minecraft.network.Connection import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.common.ClientboundPingPacket -import net.minecraft.network.protocol.ping.ServerboundPingRequestPacket -import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket -import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket +import net.minecraft.network.protocol.configuration.ClientboundSelectKnownPacks +import net.minecraft.server.MinecraftServer +import net.minecraft.server.network.ConfigurationTask +import net.minecraft.server.network.ServerConfigurationPacketListenerImpl +import net.minecraft.server.network.config.ServerResourcePackConfigurationTask import org.bukkit.plugin.java.JavaPlugin import team.unnamed.creative.ResourcePack +import java.util.* class PackyPlugin : JavaPlugin() { @@ -76,8 +83,6 @@ class PackyPlugin : JavaPlugin() { PackyServer.registerConfigPacketHandler() } - - private val templateFormat = ConfigFormats( listOf( Format( diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt b/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt index f1c6fb4..8a79b94 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt @@ -24,7 +24,13 @@ import net.minecraft.network.protocol.common.ClientboundPingPacket import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket import net.minecraft.network.protocol.common.ServerboundResourcePackPacket import net.minecraft.network.protocol.configuration.ClientboundFinishConfigurationPacket +import net.minecraft.network.protocol.configuration.ClientboundSelectKnownPacks import net.minecraft.network.protocol.ping.ServerboundPingRequestPacket +import net.minecraft.server.MinecraftServer +import net.minecraft.server.network.ConfigurationTask +import net.minecraft.server.network.ServerConfigurationPacketListenerImpl +import net.minecraft.server.network.config.ServerResourcePackConfigurationTask +import org.bukkit.craftbukkit.CraftServer import org.bukkit.entity.Player import org.bukkit.event.player.PlayerResourcePackStatusEvent import team.unnamed.creative.serialize.minecraft.MinecraftResourcePackWriter @@ -46,7 +52,7 @@ object PackyServer { player.sendResourcePacks(ResourcePackRequest.resourcePackRequest() .packs(resourcePack.resourcePackInfo).replace(true) .required(packy.config.force && !player.packyData.bypassForced) - .prompt(packy.config.prompt.miniMsg()) + .prompt(packy.config.prompt?.miniMsg()) ) } @@ -59,50 +65,39 @@ object PackyServer { delay(10.ticks) } - private val cachedPackyData = mutableMapOf() + private val configurationTasks = ServerConfigurationPacketListenerImpl::class.java.getDeclaredField("configurationTasks").apply { isAccessible = true } + private val startNextTaskMethod = ServerConfigurationPacketListenerImpl::class.java.getDeclaredMethod("startNextTask").apply { isAccessible = true } fun registerConfigPacketHandler() { - if (!packy.config.dispatch.sendPreJoin) return + packy.plugin.interceptClientbound { packet: Packet<*>, connection: Connection -> - if (packet !is ClientboundFinishConfigurationPacket) return@interceptClientbound packet + if (packet !is ClientboundSelectKnownPacks) return@interceptClientbound packet + val configListener = connection.packetListener as? ServerConfigurationPacketListenerImpl ?: return@interceptClientbound packet val player = connection.player?.bukkitEntity ?: return@interceptClientbound packet - if (player.resourcePackStatus != null) return@interceptClientbound packet val packyData = player.getOfflinePDC()?.decode() ?: return@interceptClientbound packet + val taskQueue = configurationTasks.get(configListener) as? Queue ?: return@interceptClientbound packet - if (packy.config.dispatch.sendPreJoinOnCached && PackyGenerator.getCachedPack(packyData.enabledPackIds) == null) - return@interceptClientbound packet + // Removes the JoinWorldTask from the Queue + val headTask = taskQueue.poll() - cachedPackyData[player.uniqueId] = packyData + // Runs next tick, after the queue progresses and is empty packy.plugin.launch { val info = PackyGenerator.getOrCreateCachedPack(packyData.enabledPackIds).await().resourcePackInfo - connection.send( - ClientboundResourcePackPushPacket( - info.id(), info.uri().toString(), info.hash(), - packy.config.force && !packyData.bypassForced, - Optional.of(PaperAdventure.asVanilla(packy.config.prompt.miniMsg())) - ) + taskQueue.add( + ServerResourcePackConfigurationTask( + MinecraftServer.ServerResourcePackInfo( + info.id(), info.uri().toString(), info.hash(), + packy.config.force && !packyData.bypassForced, + PaperAdventure.asVanilla(packy.config.prompt?.miniMsg()) + )) ) - } - - return@interceptClientbound null - } - - packy.plugin.interceptServerbound { packet: Packet<*>, connection: Connection -> - if (packet !is ServerboundResourcePackPacket || !packet.action.isTerminal) return@interceptServerbound packet - val player = connection.player?.bukkitEntity ?: return@interceptServerbound packet - val packyData = cachedPackyData[player.uniqueId] ?: return@interceptServerbound packet - val status = PlayerResourcePackStatusEvent.Status.entries.find { it.name == packet.action.name } ?: return@interceptServerbound packet - PackyGenerator.getCachedPack(packyData.enabledPackIds)?.resourcePackInfo?.id()?.takeIf { it == packet.id } ?: return@interceptServerbound packet - // Manually call event and change player-status over sending the packet - // Doing so causes some error with syncing tasks and this does effectively the same - player.resourcePackStatus = status - packy.plugin.launch { - PlayerResourcePackStatusEvent(player, packet.id, status).call() + headTask?.let(taskQueue::add) + startNextTaskMethod.invoke(configListener) } - connection.send(ClientboundFinishConfigurationPacket.INSTANCE) - cachedPackyData.remove(player.uniqueId) - return@interceptServerbound null + // Returns the ClientboundSelectKnownPacks packet, which causes the queue to continue + // Since it is now empty it does nothing, until our coroutine finishes and triggers startNextTask + return@interceptClientbound packet } } diff --git a/src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt b/src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt index 5aa2cbc..e192934 100644 --- a/src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt +++ b/src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt @@ -26,8 +26,7 @@ data class PackyConfig( @EncodeDefault(ALWAYS) val mcmeta: PackyMcMeta = PackyMcMeta(), @EncodeDefault(ALWAYS) val icon: String = "pack.png", @EncodeDefault(ALWAYS) val server: PackyServer = PackyServer(), - @EncodeDefault(ALWAYS) val dispatch: PackyDispatch = PackyDispatch(), - @EncodeDefault(ALWAYS) val prompt: String = "", + @EncodeDefault(ALWAYS) val prompt: String? = null, @EncodeDefault(ALWAYS) val force: Boolean = false, @YamlComment("What ObfuscationType to use, valid options are FULL, SIMPLE & NONE") @EncodeDefault(ALWAYS) val obfuscation: ObfuscationType = ObfuscationType.FULL, @@ -41,16 +40,6 @@ data class PackyConfig( @EncodeDefault(ALWAYS) val menu: PackyMenu = PackyMenu() ) { - @Serializable - data class PackyDispatch( - @YamlComment("Sends the pack before the player loads into the world") - val sendPreJoin: Boolean = true, - @YamlComment("If the pack has been generated and cached, allow pre-join dispatch") - val sendPreJoinOnCached: Boolean = true, - @YamlComment("The delay to wait before sending the pack") - val sendDelay: @Serializable(DurationSerializer::class) Duration = 0.seconds - ) - enum class ObfuscationType { FULL, SIMPLE, NONE } diff --git a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt index 30b9104..48dc6fd 100644 --- a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt +++ b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt @@ -1,10 +1,7 @@ package com.mineinabyss.packy.listener -import com.github.shynixn.mccoroutine.bukkit.launch -import com.mineinabyss.packy.PackyServer import com.mineinabyss.packy.components.packyData import com.mineinabyss.packy.config.packy -import kotlinx.coroutines.delay import org.bukkit.event.EventHandler import org.bukkit.event.EventPriority import org.bukkit.event.Listener @@ -12,14 +9,6 @@ import org.bukkit.event.player.PlayerJoinEvent class PlayerListener : Listener { - @EventHandler(priority = EventPriority.HIGHEST) - fun PlayerJoinEvent.sendPack() { - if (PackyServer.packServer != null && !player.hasResourcePack()) packy.plugin.launch { - delay(packy.config.dispatch.sendDelay) - PackyServer.sendPack(player) - } - } - @EventHandler(priority = EventPriority.NORMAL) fun PlayerJoinEvent.filterPackyData() { // Remove old or forced keys from enabledPackAddons