diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyDownloader.kt b/src/main/kotlin/com/mineinabyss/packy/PackyDownloader.kt index 269e078..01274c0 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyDownloader.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyDownloader.kt @@ -65,9 +65,8 @@ object PackyDownloader { fun downloadTemplates() { startupJob = packy.plugin.launch(packy.plugin.asyncDispatcher) { - packy.templates.values.filter { it.githubDownload != null } - .sortedBy { it.id } - .groupBy { it.githubDownload!!.key() } + packy.templates.filter { it.githubDownload != null } + .sortedBy { it.id }.groupBy { it.githubDownload!!.key() } .map { (_, templates) -> val templateIds = templates.joinToString { it.id } val suffix = "template" + if (templates.size > 1) "s" else "" diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt b/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt index 5d242a4..20c9905 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyGenerator.kt @@ -30,7 +30,7 @@ object PackyGenerator { ?.let { packy.defaultPack.packMeta(packy.config.mcmeta.format, it.miniMsg()) } // Add all forced packs to defaultPack - packy.templates.filterValues(PackyTemplate::required).values.mapNotNull { ResourcePacks.readToResourcePack(it.path.toFile()) }.forEach { + packy.templates.filter(PackyTemplate::required).mapNotNull { ResourcePacks.readToResourcePack(it.path.toFile()) }.forEach { ResourcePacks.mergeResourcePacks(packy.defaultPack, it) } @@ -56,7 +56,7 @@ object PackyGenerator { // Filters out all required files as they are already in defaultPack // Filter all TemplatePacks that are not default or not in players enabledPackAddons - packy.templates.values.filter { !it.required && it.id in templateIds } + packy.templates.filter { !it.required && it.id in templateIds } .mapNotNull { ResourcePacks.readToResourcePack(it.path.toFile()) } .forEach { ResourcePacks.mergeResourcePacks(cachedPack, it) } diff --git a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt index 20d67bb..0cc8af5 100644 --- a/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt +++ b/src/main/kotlin/com/mineinabyss/packy/PackyPlugin.kt @@ -53,9 +53,9 @@ class PackyPlugin : JavaPlugin() { DI.add(object : PackyContext { override val plugin = this@PackyPlugin override val config: PackyConfig by config("config", dataFolder.toPath(), PackyConfig()) - override val templates: Map = config( - "templates", dataFolder.toPath(), PackyTemplates(), formats = templateFormat - ).getOrLoad().templateMap + override val templates: PackyTemplates = config( + "templates", dataPath, PackyTemplates(), formats = templateFormat + ).getOrLoad() override val accessToken: PackyAccessToken by config("accessToken", dataFolder.toPath(), PackyAccessToken()) override val defaultPack: ResourcePack = ResourcePack.resourcePack() override val logger by plugin.observeLogger() diff --git a/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt b/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt index cd43765..914f989 100644 --- a/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt +++ b/src/main/kotlin/com/mineinabyss/packy/components/PackyData.kt @@ -13,7 +13,7 @@ import org.bukkit.entity.Player @Serializable @SerialName("packy:packy_data") data class PackyData( - val enabledPackAddons: MutableSet = packy.templates.values.filter { !it.required && it.default }.toMutableSet(), + val enabledPackAddons: MutableSet = packy.templates.filter { !it.required && it.default }.toMutableSet(), var bypassForced: Boolean = false ) { val enabledPackIds get() = enabledPackAddons.map { it.id }.toSortedSet() diff --git a/src/main/kotlin/com/mineinabyss/packy/config/PackyContext.kt b/src/main/kotlin/com/mineinabyss/packy/config/PackyContext.kt index d772742..0faf5ae 100644 --- a/src/main/kotlin/com/mineinabyss/packy/config/PackyContext.kt +++ b/src/main/kotlin/com/mineinabyss/packy/config/PackyContext.kt @@ -12,7 +12,7 @@ interface PackyContext { val plugin: PackyPlugin val config: PackyConfig val defaultPack: ResourcePack - val templates: Map + val templates: PackyTemplates val accessToken: PackyAccessToken val logger: ComponentLogger } diff --git a/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt b/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt index 99d7057..da84747 100644 --- a/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt +++ b/src/main/kotlin/com/mineinabyss/packy/config/PackyTemplate.kt @@ -1,29 +1,46 @@ 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.EncodeDefault +import kotlinx.serialization.* import kotlinx.serialization.EncodeDefault.Mode.NEVER -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable 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.* -@OptIn(ExperimentalSerializationApi::class) -@Serializable -data class PackyTemplates(val templates: List = listOf()) { - @EncodeDefault(NEVER) - val templateMap: Map = templates.associateBy { it.name } +@Serializable(with = PackyTemplates.Serializer::class) +data class PackyTemplates(private val templates: List = listOf()) { + + @Transient private val ids = templates.map { it.id } - fun component2(): Map = templateMap + operator fun contains(template: @UnsafeVariance PackyTemplate): Boolean = templates.contains(template) + operator fun contains(id: @UnsafeVariance String): Boolean = ids.contains(id) + fun forEach(action: (PackyTemplate) -> Unit) = templates.forEach(action) + fun filter(filter: (PackyTemplate) -> Boolean) = templates.filter(filter) + fun find(predicate: (PackyTemplate) -> Boolean) = templates.find(predicate) + operator fun get(id: String) = templates.find { it.id == id } + + class Serializer : InnerSerializer, PackyTemplates>( + "packy:templates", + MapSerializer(String.serializer(), PackyTemplate.serializer()), + { PackyTemplates(it.map { it.value.copy(id = it.key) }) }, + { it.templates.associateBy { it.id } } + ) } @Serializable +@Polymorphic @OptIn(ExperimentalSerializationApi::class) data class PackyTemplate( - val name: String, + // This is blank by default to avoid marking it as null + // The Serializer in PackyTemplates will always ensure the id is properly set + @Transient val id: String = "", val default: Boolean = false, val required: Boolean = false, @EncodeDefault(NEVER) val conflictsWith: Set = setOf(), @@ -34,8 +51,6 @@ data class PackyTemplate( @Transient var triggerListener: Listener? = null - val id: String get() = name - val path: Path get() = filePath?.takeIf { it.isNotEmpty() }?.let { packy.plugin.dataFolder.parentFile.toPath() / it } ?: (packy.plugin.dataFolder.toPath() / "templates" / id) .let { if (it.exists() && it.isDirectory()) it else Path(it.pathString + ".zip") } diff --git a/src/main/kotlin/com/mineinabyss/packy/helpers/PackyHelpers.kt b/src/main/kotlin/com/mineinabyss/packy/helpers/PackyHelpers.kt index 1104f13..7ea2ef2 100644 --- a/src/main/kotlin/com/mineinabyss/packy/helpers/PackyHelpers.kt +++ b/src/main/kotlin/com/mineinabyss/packy/helpers/PackyHelpers.kt @@ -19,14 +19,14 @@ fun Response.downloadZipFromGithubResponse(vararg templates: PackyTemplate) { inputStream.copyTo(this) }.toByteArray() } ?: run { - packy.logger.e("${templates.joinToString { it.name }} has no response body, skipping...") + packy.logger.e("${templates.joinToString { it.id }} has no response body, skipping...") return } templates.forEach { template -> val githubDownload = template.githubDownload if (githubDownload == null) { - packy.logger.e("${template.name} has no githubDownload, skipping...") + packy.logger.e("${template.id} has no githubDownload, skipping...") return@forEach } diff --git a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt index 48dc6fd..431e6a1 100644 --- a/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt +++ b/src/main/kotlin/com/mineinabyss/packy/listener/PlayerListener.kt @@ -12,13 +12,11 @@ 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.keys || t.required } + 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.values }.forEach { template -> + player.packyData.enabledPackAddons.filter { it in packy.templates }.forEach { template -> player.packyData.enabledPackAddons -= template - packy.templates.entries.find { it.key == template.id }?.value?.let { - player.packyData.enabledPackAddons += it - } + packy.templates[template.id]?.let { player.packyData.enabledPackAddons += it } } } } diff --git a/src/main/kotlin/com/mineinabyss/packy/listener/TemplateLoadTriggers.kt b/src/main/kotlin/com/mineinabyss/packy/listener/TemplateLoadTriggers.kt index cd22d6f..a6d6c6a 100644 --- a/src/main/kotlin/com/mineinabyss/packy/listener/TemplateLoadTriggers.kt +++ b/src/main/kotlin/com/mineinabyss/packy/listener/TemplateLoadTriggers.kt @@ -29,12 +29,12 @@ object TemplateLoadTriggers { fun registerTemplateHandlers() { unregisterTemplateHandlers() - packy.templates.values.forEach { it.loadTrigger.registerLoadHandler(it) } + packy.templates.forEach { it.loadTrigger.registerLoadHandler(it) } } fun unregisterTemplateHandlers() { runCatching { - packy.templates.values.forEach { t -> t.triggerListener?.let { packy.plugin.unregisterListeners(it) } } + packy.templates.forEach { t -> t.triggerListener?.let { packy.plugin.unregisterListeners(it) } } } } } 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 81e13a6..7e28e1c 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackPicker.kt @@ -12,14 +12,13 @@ import org.bukkit.entity.Player object PackPicker { fun addPack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { - if (pack !in packy.templates.keys) return null - return packy.templates.entries.find { it.key == pack }?.let { (id, template) -> + return packy.templates[pack]?.let { template -> val removedConflicting = player.removeConflictingPacks(template).map { it.id } packyData.enabledPackAddons += template - if ((sender as? Player)?.uniqueId != player.uniqueId) sender.success("TemplatePack $id was added to ${player.name}'s addon-packs") + 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 $id was added to your addon-packs") + player.success("The template ${template.id} was added to your addon-packs") if (removedConflicting.isNotEmpty()) { sender.warn("Removed conflicting pack-templates: ${removedConflicting.joinToString(", ")}") } @@ -36,13 +35,12 @@ object PackPicker { } fun removePack(scope: PackyUIScope, player: Player, packyData: PackyData, pack: String, sender: CommandSender = player): Unit? { - if (pack !in packy.templates.keys) return null - return packy.templates.entries.find { it.key == pack }?.let { (id, template) -> + return packy.templates.find { it.id == pack }?.let { template -> packyData.enabledPackAddons -= template scope.changedAction = { - if ((sender as? Player)?.uniqueId != player.uniqueId) sender.success("TemplatePack $id was removed from ${player.name}'s addon-packs") - player.success("TemplatePack $id was removed from your addon-packs") + 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") } } ?: run { scope.changedAction = { 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 e03801a..d5c3170 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackyMainMenu.kt @@ -24,8 +24,7 @@ fun PackyMenu() { var packs by remember { mutableStateOf(subPackList[subMenu]!!) } if (subMenu.packs.size == 1) { - val templateId = subMenu.packs.keys.firstOrNull() ?: return@map - packy.templates.entries.find { it.key == templateId }?.value ?: return@map + val templateId = subMenu.packs.keys.firstOrNull()?.takeIf { it in packy.templates } ?: return@map Item(subMenu.button.toItemStack(), subMenu.modifiers.toModifier().clickable { // Return if the task returns null, meaning button was spammed whilst a set was currently generating 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 5ec2064..085ec1b 100644 --- a/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt +++ b/src/main/kotlin/com/mineinabyss/packy/menus/picker/PackySubMenu.kt @@ -15,7 +15,7 @@ fun PackySubMenu(subMenu: PackyConfig.PackySubMenu) { val scope = PackyScopeProvider.current val player = scope.player subMenu.packs.forEach { (templateId, pack) -> - val template = packy.templates.entries.find { it.key == templateId }?.value ?: return@forEach + val template = packy.templates[templateId] ?: return@forEach Button(pack.modifiers.toModifier(), onClick = { when { template !in player.packyData.enabledPackAddons -> PackPicker.addPack(scope, player, packyData, templateId)