Skip to content

Commit

Permalink
feat: add ServerConfigurationTask for ConfigPhase ResourcePack
Browse files Browse the repository at this point in the history
  • Loading branch information
Boy0000 committed Jul 22, 2024
1 parent 53a4a3d commit 2feaa34
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 46 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
group=com.mineinabyss
version=0.5
idofrontVersion=0.24.12
version=0.6
idofrontVersion=0.24.13
17 changes: 15 additions & 2 deletions src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,37 @@ 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
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.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.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() {

Expand Down Expand Up @@ -68,8 +83,6 @@ class PackyPlugin : JavaPlugin() {
PackyServer.registerConfigPacketHandler()
}



private val templateFormat = ConfigFormats(
listOf(
Format(
Expand Down
71 changes: 31 additions & 40 deletions src/main/kotlin/com/mineinabyss/packy/PackyServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.github.shynixn.mccoroutine.bukkit.launch
import com.github.shynixn.mccoroutine.bukkit.ticks
import com.mineinabyss.geary.papermc.datastore.decode
import com.mineinabyss.idofront.events.call
import com.mineinabyss.idofront.messaging.broadcast
import com.mineinabyss.idofront.nms.interceptClientbound
import com.mineinabyss.idofront.nms.interceptServerbound
import com.mineinabyss.idofront.nms.nbt.getOfflinePDC
Expand All @@ -13,26 +12,25 @@ import com.mineinabyss.packy.components.PackyData
import com.mineinabyss.packy.components.packyData
import com.mineinabyss.packy.config.packy
import com.mineinabyss.packy.helpers.TemplateIds
import io.netty.channel.Channel
import io.netty.channel.ChannelDuplexHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelPromise
import io.papermc.paper.adventure.PaperAdventure
import io.papermc.paper.network.ChannelInitializeListenerHolder
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import net.kyori.adventure.resource.ResourcePackRequest
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor
import net.minecraft.network.Connection
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.common.ClientboundDisconnectPacket
import net.minecraft.network.protocol.common.ClientboundResourcePackPopPacket
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 org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.entity.CraftPlayer
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
Expand All @@ -54,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())
)
}

Expand All @@ -67,46 +65,39 @@ object PackyServer {
delay(10.ticks)
}

private val cachedPackyData = mutableMapOf<UUID, PackyData>()
private val configurationTasks = ServerConfigurationPacketListenerImpl::class.java.getDeclaredField("configurationTasks").apply { isAccessible = true }
private val startNextTaskMethod = ServerConfigurationPacketListenerImpl::class.java.getDeclaredMethod("startNextTask").apply { isAccessible = true }
fun registerConfigPacketHandler() {

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<PackyData>() ?: return@interceptClientbound packet
val taskQueue = configurationTasks.get(configListener) as? Queue<ConfigurationTask> ?: 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
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mineinabyss.packy.config

import co.touchlab.kermit.Severity
import com.charleskorn.kaml.YamlComment
import com.mineinabyss.guiy.modifiers.Modifier
import com.mineinabyss.guiy.modifiers.placement.absolute.at
Expand All @@ -14,6 +13,7 @@ import kotlinx.serialization.EncodeDefault.Mode.ALWAYS
import kotlinx.serialization.EncodeDefault.Mode.NEVER
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import net.kyori.adventure.resource.ResourcePackStatus
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
Expand All @@ -26,7 +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 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,
Expand Down

0 comments on commit 2feaa34

Please sign in to comment.