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 3911019 commit febda9b
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 63 deletions.
19 changes: 12 additions & 7 deletions src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +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.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() {

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



private val templateFormat = ConfigFormats(
listOf(
Format(
Expand Down
61 changes: 28 additions & 33 deletions src/main/kotlin/com/mineinabyss/packy/PackyServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
)
}

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

Expand Down
13 changes: 1 addition & 12 deletions src/main/kotlin/com/mineinabyss/packy/config/PackyConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
11 changes: 0 additions & 11 deletions src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
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
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
Expand Down

0 comments on commit febda9b

Please sign in to comment.