diff --git a/src/main/kotlin/com/mineinabyss/packy/PackObfuscator.kt b/src/main/kotlin/com/mineinabyss/packy/PackObfuscator.kt index da8bc10..c260c61 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackObfuscator.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackObfuscator.kt @@ -62,7 +62,7 @@ class PackObfuscator(private val resourcePack: ResourcePack) { } private fun obfuscateModels() { - resourcePack.models().filterNotNull().forEach { obfuscateModel(it) } + resourcePack.models().filterNotNull().forEach(::obfuscateModel) obfuscatedModels.forEach { resourcePack.removeModel(it.originalModel.key()) @@ -149,20 +149,20 @@ class PackObfuscator(private val resourcePack: ResourcePack) { private fun obfuscateModel(model: Model) = - obfuscatedModels.findObf(model.key()) ?: model.obfuscateModelTextures().obfuscateOverrides() + obfuscatedModels.findObf(model.key()) ?: model.obfuscateModelTextures().obfuscateParentModel().obfuscateOverrides() private fun Model.obfuscateModelTextures(): Model { obfuscatedModels.findObf(this.key())?.let { return it } + val layers = textures().layers().filter { it.key() != null }.map { modelTexture -> - obfuscateItemTexture(modelTexture)?.key()?.let { ModelTexture.ofKey(it) } ?: modelTexture + obfuscateModelTexture(modelTexture)?.key()?.let(ModelTexture::ofKey) ?: modelTexture } val variables = textures().variables().map { variable -> - variable.key to (obfuscateItemTexture(variable.value)?.key() - ?.let(ModelTexture::ofKey) ?: variable.value) + variable.key to (obfuscateModelTexture(variable.value)?.key()?.let(ModelTexture::ofKey) ?: variable.value) }.toMap() val particle = textures().particle() - ?.let { p -> obfuscateItemTexture(p)?.key()?.let { ModelTexture.ofKey(it) } ?: p } + ?.let { p -> obfuscateModelTexture(p)?.key()?.let { ModelTexture.ofKey(it) } ?: p } val modelTextures = ModelTextures.builder().layers(layers).variables(variables).particle(particle).build() return this.toBuilder().textures(modelTextures).build() } @@ -173,12 +173,24 @@ class PackObfuscator(private val resourcePack: ResourcePack) { .uvLock(uvLock()).weight(weight()).x(x()).y(y()).build() } + private fun Model.obfuscateParentModel(): Model { + val parent = parent() ?: return this + obfuscatedModels.findObf(key())?.let { return it } + + return toBuilder().parent( + obfuscatedModels.findObf(parent)?.key() + ?: resourcePack.takeUnless { parent == key() }?.model(parent)?.let(::obfuscateModel)?.key() + ?: parent + ).build() + } + private fun Model.obfuscateOverrides(): Model = obfuscatedModels.findObf(key()) ?: toBuilder().overrides( overrides().filterNotNull().map { override -> - if (ResourcePacks.defaultVanillaResourcePack?.model(override.model()) != null) return@map override - val modelKey = obfuscatedModels.findObf(override.model())?.key() - ?: resourcePack.takeUnless { override.model() == this.key() }?.model(override.model())?.let { obfuscateModel(it) }?.key() - ?: override.model() + val overrideKey = override.model() + if (ResourcePacks.defaultVanillaResourcePack?.model(overrideKey) != null) return@map override + val modelKey = obfuscatedModels.findObf(overrideKey)?.key() + ?: resourcePack.takeUnless { overrideKey == this.key() }?.model(overrideKey)?.let(::obfuscateModel)?.key() + ?: overrideKey return@map ItemOverride.of(modelKey, override.predicate()) } @@ -193,7 +205,7 @@ class PackObfuscator(private val resourcePack: ResourcePack) { this.toBuilder().key(this.key().obfuscateKey()).build() .also { obfuscatedTextures += ObfuscatedTexture(this@obfuscate, it) } - private fun obfuscateItemTexture(modelTexture: ModelTexture): Texture? { + private fun obfuscateModelTexture(modelTexture: ModelTexture): Texture? { val keyPng = modelTexture.key()?.removeSuffix(".png") ?: return null return obfuscatedTextures.findObf(keyPng) ?: resourcePack.texture(keyPng)?.obfuscate() } diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyCommands.kt b/src/main/kotlin/com/mineinabyss/packy/PackyCommands.kt index ac4b213..cb759f2 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyCommands.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyCommands.kt @@ -4,11 +4,15 @@ import com.github.shynixn.mccoroutine.bukkit.launch import com.mineinabyss.guiy.inventory.guiy import com.mineinabyss.idofront.commands.brigadier.commands import com.mineinabyss.idofront.messaging.error +import com.mineinabyss.idofront.messaging.info import com.mineinabyss.idofront.messaging.success +import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.packy.components.packyData import com.mineinabyss.packy.config.packy import com.mineinabyss.packy.menus.picker.PackyMainMenu import io.papermc.paper.command.brigadier.argument.ArgumentTypes +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.Bukkit import org.bukkit.entity.Player @@ -58,6 +62,24 @@ object PackyCommands { } } } + "debug" { + playerExecutes { + + player.packyData.templates.mapNotNull { (packy.templates[it.key] ?: return@mapNotNull null) to it.value } + .map { + Component.textOfChildren( + Component.text(it.first.id, when { + it.first.default && it.first.required -> NamedTextColor.GOLD + it.first.default -> NamedTextColor.YELLOW + it.first.required -> NamedTextColor.RED + else -> NamedTextColor.AQUA + }), + Component.text(": "), + Component.text(it.second, if (it.second) NamedTextColor.GREEN else NamedTextColor.DARK_RED), + ) + }.forEach(sender::sendMessage) + } + } } } } diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt b/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt index 20c9905..a5bee2c 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt @@ -12,7 +12,6 @@ import com.mineinabyss.packy.helpers.TemplateIds import kotlinx.coroutines.* import team.unnamed.creative.ResourcePack import team.unnamed.creative.base.Writable -import team.unnamed.creative.sound.SoundRegistry import kotlin.io.path.div import kotlin.io.path.exists @@ -62,6 +61,7 @@ object PackyGenerator { PackObfuscator(cachedPack).obfuscatePack() + ResourcePacks.resourcePackWriter.writeToZipFile(packy.plugin.dataFolder.resolve("test2.zip"), cachedPack) val builtPack = ResourcePacks.resourcePackWriter.build(cachedPack) PackyPack(builtPack, templateIds).apply { cachedPacks[templateIds] = this diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt index 2b21592..b66a1fd 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt @@ -65,7 +65,6 @@ class PackyPlugin : JavaPlugin() { PackyDownloader.downloadTemplates() TemplateLoadTriggers.registerTemplateHandlers() PackyGenerator.setupRequiredPackTemplates() - PackyServer.cacheDefaultPackData() PackyServer.registerConfigPacketHandler() } diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt b/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt index a01726e..a33b526 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyServer.kt @@ -7,7 +7,10 @@ import com.mineinabyss.idofront.nms.interceptClientbound import com.mineinabyss.idofront.nms.nbt.getOfflinePDC import com.mineinabyss.idofront.resourcepacks.ResourcePacks import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.packy.PackyGenerator.cachedPacks +import com.mineinabyss.packy.PackyGenerator.cachedPacksByteArray import com.mineinabyss.packy.components.PackyData +import com.mineinabyss.packy.components.PackyPack import com.mineinabyss.packy.components.packyData import com.mineinabyss.packy.config.packy import com.mineinabyss.packy.helpers.TemplateIds @@ -25,6 +28,7 @@ import net.minecraft.server.network.ConfigurationTask import net.minecraft.server.network.ServerConfigurationPacketListenerImpl import net.minecraft.server.network.config.ServerResourcePackConfigurationTask import org.bukkit.entity.Player +import team.unnamed.creative.ResourcePack import team.unnamed.creative.server.ResourcePackServer import team.unnamed.creative.server.handler.ResourcePackRequestHandler import java.net.URI @@ -34,7 +38,6 @@ import java.util.concurrent.Executors object PackyServer { var packServer: ResourcePackServer? = null - private lateinit var builtDefaultPack: ByteArray suspend fun sendPack(player: Player) { val templateIds = player.packyData.enabledPackIds @@ -48,10 +51,6 @@ object PackyServer { ) } - fun cacheDefaultPackData() { - builtDefaultPack = ResourcePacks.resourcePackWriter.build(packy.defaultPack).data().toByteArray() - } - private suspend fun Player.sendPackGeneratingActionBar() { sendActionBar(Component.text("Generating ResourcePack.", NamedTextColor.RED)) delay(10.ticks) @@ -68,9 +67,9 @@ object PackyServer { packy.plugin.interceptClientbound { packet: Packet<*>, connection: Connection -> if (packet !is ClientboundSelectKnownPacks) return@interceptClientbound packet val configListener = connection.packetListener as? ServerConfigurationPacketListenerImpl ?: return@interceptClientbound packet - val player = connection.player?.bukkitEntity ?: return@interceptClientbound packet - val packyData = player.getOfflinePDC()?.decode() ?: return@interceptClientbound packet val taskQueue = configurationTasks.get(configListener) as? Queue ?: return@interceptClientbound packet + val offlinePdc = connection.player?.bukkitEntity?.getOfflinePDC() ?: return@interceptClientbound packet + val packyData = offlinePdc.decode() ?: PackyData() // Removes the JoinWorldTask from the Queue val headTask = taskQueue.poll() @@ -118,8 +117,8 @@ object PackyServer { } private val handler = ResourcePackRequestHandler { _, exchange -> - val data = exchange.requestURI.parseTemplateIds()?.takeIf { it.isNotEmpty() } - ?.let(PackyGenerator.cachedPacksByteArray::get) ?: builtDefaultPack + val data = exchange.requestURI.parseTemplateIds()?.let(cachedPacksByteArray::get) + ?: ResourcePacks.resourcePackWriter.build(packy.defaultPack).data().toByteArray() exchange.responseHeaders["Content-Type"] = "application/zip" exchange.sendResponseHeaders(200, data.size.toLong()) exchange.responseBody.use { responseStream -> responseStream.write(data) } diff --git a/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt b/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt index 914f989..ddbda1a 100644 --- a/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt +++ b/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt @@ -4,31 +4,21 @@ import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.geary.serialization.getOrSetPersisting import com.mineinabyss.geary.serialization.setPersisting import com.mineinabyss.packy.config.PackyTemplate -import com.mineinabyss.packy.config.conflictsWith import com.mineinabyss.packy.config.packy import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.bukkit.entity.Player +import java.util.SortedMap @Serializable @SerialName("packy:packy_data") data class PackyData( - val enabledPackAddons: MutableSet = packy.templates.filter { !it.required && it.default }.toMutableSet(), + val templates: MutableMap = packy.templates.associate { it.id to (it.default || it.required) }.toMutableMap(), var bypassForced: Boolean = false ) { - val enabledPackIds get() = enabledPackAddons.map { it.id }.toSortedSet() + val enabledPackIds get() = templates.filterValues { it }.keys.toSortedSet() } var Player.packyData get() = this.toGeary().getOrSetPersisting { PackyData() } - set(value) { - this.toGeary().setPersisting(value) - } - -fun Player.removeConflictingPacks(template: PackyTemplate): Set { - return mutableSetOf().apply { - packyData.enabledPackAddons.removeIf { t -> - t.conflictsWith(template).let { if (it) this.add(t); it } - } - }.toSet() -} + set(value) { this.toGeary().setPersisting(value) } diff --git a/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt b/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt index da84747..01b1a9d 100644 --- a/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt +++ b/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt @@ -1,8 +1,6 @@ package com.mineinabyss.packy.config import com.mineinabyss.geary.serialization.serializers.InnerSerializer -import com.mineinabyss.geary.serialization.serializers.PolymorphicListAsMapSerializer -import com.mineinabyss.idofront.messaging.broadcastVal import com.mineinabyss.packy.listener.LoadTrigger import kotlinx.serialization.* import kotlinx.serialization.EncodeDefault.Mode.NEVER @@ -10,7 +8,6 @@ import kotlinx.serialization.Transient import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.serializer import org.bukkit.event.Listener -import java.io.File import java.nio.file.Path import kotlin.io.path.* @@ -24,6 +21,7 @@ data class PackyTemplates(private val templates: List = listOf()) fun forEach(action: (PackyTemplate) -> Unit) = templates.forEach(action) fun filter(filter: (PackyTemplate) -> Boolean) = templates.filter(filter) fun find(predicate: (PackyTemplate) -> Boolean) = templates.find(predicate) + fun associate(transform: (PackyTemplate) -> Pair) = templates.associate(transform) operator fun get(id: String) = templates.find { it.id == id } class Serializer : InnerSerializer, PackyTemplates>( @@ -49,6 +47,9 @@ data class PackyTemplate( @EncodeDefault(NEVER) private val filePath: String? = null ) { + fun conflictsWith(template: PackyTemplate) = + template.id in this.conflictsWith || this.id in template.conflictsWith + @Transient var triggerListener: Listener? = null val path: Path get() = filePath?.takeIf { it.isNotEmpty() }?.let { packy.plugin.dataFolder.parentFile.toPath() / it } @@ -69,7 +70,3 @@ data class PackyTemplate( @Serializable data class PackyAccessToken(internal val token: String = "") - -fun PackyTemplate.conflictsWith(template: PackyTemplate) = - template.id in this.conflictsWith || this.id in template.conflictsWith - diff --git a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt index 431e6a1..e144936 100644 --- a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt +++ b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt @@ -1,6 +1,7 @@ package com.mineinabyss.packy.listener import com.mineinabyss.packy.components.packyData +import com.mineinabyss.packy.config.PackyTemplate import com.mineinabyss.packy.config.packy import org.bukkit.event.EventHandler import org.bukkit.event.EventPriority @@ -11,12 +12,10 @@ class PlayerListener : Listener { @EventHandler(priority = EventPriority.NORMAL) fun PlayerJoinEvent.filterPackyData() { - // Remove old or forced keys from enabledPackAddons - player.packyData.enabledPackAddons.removeIf { t -> t.id !in packy.templates || t.required } - // Ensure that PackyTemplates are up-to-date - player.packyData.enabledPackAddons.filter { it in packy.templates }.forEach { template -> - player.packyData.enabledPackAddons -= template - packy.templates[template.id]?.let { player.packyData.enabledPackAddons += it } - } + val packyData = player.packyData + // Remove old or required keys from templates + packyData.templates.keys.filter { packy.templates[it] == null }.forEach(packyData.templates::remove) + // Add missing template keys + packy.templates.forEach { template -> packyData.templates.computeIfAbsent(template.id) { template.default || template.required } } } } diff --git a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt index 7e28e1c..461cce4 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt @@ -5,22 +5,22 @@ import com.mineinabyss.idofront.messaging.success import com.mineinabyss.idofront.messaging.warn import com.mineinabyss.packy.components.PackyData import com.mineinabyss.packy.components.packyData -import com.mineinabyss.packy.components.removeConflictingPacks +import com.mineinabyss.packy.config.PackyTemplate import com.mineinabyss.packy.config.packy import org.bukkit.command.CommandSender import org.bukkit.entity.Player object PackPicker { - fun addPack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { + fun enablePack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { return packy.templates[pack]?.let { template -> - val removedConflicting = player.removeConflictingPacks(template).map { it.id } - packyData.enabledPackAddons += template + val disabledConflicting = disableConflictingPacks(player, template).map { it.id } + packyData.templates[template.id] = true if ((sender as? Player)?.uniqueId != player.uniqueId) sender.success("TemplatePack ${template.id} was added to ${player.name}'s addon-packs") scope.changedAction = { player.success("The template ${template.id} was added to your addon-packs") - if (removedConflicting.isNotEmpty()) { - sender.warn("Removed conflicting pack-templates: ${removedConflicting.joinToString(", ")}") + if (disabledConflicting.isNotEmpty()) { + sender.warn("Disabled conflicting pack-templates: ${disabledConflicting.joinToString(", ")}") } } } ?: run { @@ -34,13 +34,13 @@ object PackPicker { } } - fun removePack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { + fun disablePack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { return packy.templates.find { it.id == pack }?.let { template -> - packyData.enabledPackAddons -= template + packyData.templates[template.id] = false scope.changedAction = { if ((sender as? Player)?.uniqueId != player.uniqueId) sender.success("TemplatePack ${template.id} was removed from ${player.name}'s addon-packs") - player.success("TemplatePack ${template.id} was removed from your addon-packs") + player.success("TemplatePack ${template.id} was disabled from your addon-packs") } } ?: run { scope.changedAction = { @@ -52,4 +52,10 @@ object PackPicker { } } } + + private fun disableConflictingPacks(player: Player, template: PackyTemplate): Set { + return player.packyData.templates.keys.mapNotNull(packy.templates::get).filter(template::conflictsWith).toSet().also { + player.packyData.templates.putAll(it.associate { it.id to false }) + } + } } diff --git a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt index d5c3170..446998b 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt @@ -29,8 +29,8 @@ fun PackyMenu() { Item(subMenu.button.toItemStack(), subMenu.modifiers.toModifier().clickable { // Return if the task returns null, meaning button was spammed whilst a set was currently generating when { - templateId !in packyData.enabledPackIds -> PackPicker.addPack(scope, player, packyData, templateId) - else -> PackPicker.removePack(scope, player, packyData, templateId) + templateId !in packyData.enabledPackIds -> PackPicker.enablePack(scope, player, packyData, templateId) + else -> PackPicker.disablePack(scope, player, packyData, templateId) } ?: return@clickable scope.nav.refresh() @@ -42,14 +42,14 @@ fun PackyMenu() { ) PackyConfig.SubMenuType.CYCLING -> { - val templateId = packyData.enabledPackAddons.firstOrNull { it.id in subMenu.packs.keys }?.id ?: packs.first().first + val templateId = packyData.enabledPackIds.firstOrNull(subMenu.packs.keys::contains) ?: packs.first().first val pack = subMenu.packs[templateId] ?: return val currentTemplateIndex = packs.indexOf(templateId to pack) val nextTemplateId = packs[(currentTemplateIndex + 1) % packs.size].first CycleButton(subMenu, pack) { // Return if the task returns null, meaning button was spammed whilst a set was currently generating - PackPicker.addPack(scope, player, packyData, nextTemplateId) ?: return@CycleButton + PackPicker.enablePack(scope, player, packyData, nextTemplateId) ?: return@CycleButton packs = packs.rotatedLeft() scope.nav.refresh() diff --git a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyNavigation.kt b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyNavigation.kt index 17b39ca..55e685b 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyNavigation.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyNavigation.kt @@ -34,7 +34,7 @@ class PackyUIScope(val player: Player) { fun PackyMainMenu(player: Player) { val owner = LocalGuiyOwner.current val scope = remember { PackyUIScope(player) } - var packyData: PackyData by remember { mutableStateOf(PackyData(mutableSetOf())) } + var packyData: PackyData by remember { mutableStateOf(PackyData(mutableMapOf())) } LaunchedEffect(Unit) { withContext(packy.plugin.minecraftDispatcher) { packyData = player.packyData diff --git a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt index 085ec1b..bf66072 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt @@ -15,11 +15,11 @@ fun PackySubMenu(subMenu: PackyConfig.PackySubMenu) { val scope = PackyScopeProvider.current val player = scope.player subMenu.packs.forEach { (templateId, pack) -> - val template = packy.templates[templateId] ?: return@forEach + val template = packy.templates[templateId]?.id ?: return@forEach Button(pack.modifiers.toModifier(), onClick = { when { - template !in player.packyData.enabledPackAddons -> PackPicker.addPack(scope, player, packyData, templateId) - else -> PackPicker.removePack(scope, player, packyData, templateId) + template !in player.packyData.templates -> PackPicker.enablePack(scope, player, packyData, templateId) + else -> PackPicker.disablePack(scope, player, packyData, templateId) } scope.nav.back() }