From bb10e33db622e5805e7aa8de048f380715c0d478 Mon Sep 17 00:00:00 2001 From: Auxilor Date: Sat, 3 Jun 2023 16:55:58 +0100 Subject: [PATCH] Initial project outline --- build.gradle.kts | 20 +++++- .../com/willfp/ecomenus/EcoMenusPlugin.kt | 16 +++++ .../ecomenus/commands/DynamicMenuCommand.kt | 21 ++++++ .../components/PositionedComponent.kt | 39 +++++++++++ .../ecomenus/components/impl/BackButton.kt | 32 +++++++++ .../ecomenus/components/impl/CloseButton.kt | 26 +++++++ .../willfp/ecomenus/config/ConfigCategory.kt | 58 ++++++++++++++++ .../com/willfp/ecomenus/config/FoundConfig.kt | 27 ++++++++ .../ecomenus/config/IdentifiedConfig.kt | 8 +++ .../com/willfp/ecomenus/menus/EcoMenu.kt | 22 ++++++ .../com/willfp/ecomenus/menus/EcoMenus.kt | 26 +++++++ .../kotlin/com/willfp/ecomenus/menus/Menu.kt | 69 +++++++++++++++++++ .../core-plugin/src/main/resources/eco.yml | 2 +- .../core-plugin/src/main/resources/lang.yml | 2 +- .../src/main/resources/menus/_example.yml | 40 +++++++++++ 15 files changed, 405 insertions(+), 3 deletions(-) create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/commands/DynamicMenuCommand.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/PositionedComponent.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/BackButton.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/CloseButton.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/ConfigCategory.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/FoundConfig.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/IdentifiedConfig.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenu.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenus.kt create mode 100644 eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/Menu.kt create mode 100644 eco-core/core-plugin/src/main/resources/menus/_example.yml diff --git a/build.gradle.kts b/build.gradle.kts index 87c07ae..fed4f4d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,9 +35,10 @@ allprojects { } dependencies { - compileOnly("com.willfp:eco:6.53.0") + compileOnly("com.willfp:eco:6.63.0") compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.7.10") + implementation("com.willfp:ecomponent:1.4.1") } java { @@ -46,6 +47,10 @@ allprojects { } tasks { + shadowJar { + relocate("com.willfp.ecomponent", "com.willfp.ecomenus.ecomponent") + } + compileKotlin { kotlinOptions { jvmTarget = "17" @@ -73,3 +78,16 @@ allprojects { } } } + +tasks { + clean { + doLast { + file("${rootDir}/bin").deleteRecursively() + } + } + + shadowJar { + destinationDirectory.set(file("$rootDir/bin/")) + archiveFileName.set("${project.name} v${project.version}.jar") + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/EcoMenusPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/EcoMenusPlugin.kt index 7b277b0..d845e58 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/EcoMenusPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/EcoMenusPlugin.kt @@ -1,7 +1,23 @@ package com.willfp.ecomenus import com.willfp.eco.core.EcoPlugin +import com.willfp.ecomenus.config.ConfigCategory +import com.willfp.ecomenus.menus.EcoMenus class EcoMenusPlugin : EcoPlugin() { + private val categories = setOf( + EcoMenus + ) + override fun handleEnable() { + for (category in categories) { + category.copyConfigs(this) + } + } + + override fun handleReload() { + for (category in categories) { + category.reload(this) + } + } } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/commands/DynamicMenuCommand.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/commands/DynamicMenuCommand.kt new file mode 100644 index 0000000..68e7a23 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/commands/DynamicMenuCommand.kt @@ -0,0 +1,21 @@ +package com.willfp.ecomenus.commands + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.command.impl.PluginCommand +import com.willfp.ecomenus.menus.EcoMenu +import org.bukkit.entity.Player + +class DynamicMenuCommand( + plugin: EcoPlugin, + private val menu: EcoMenu, + commandName: String +) : PluginCommand( + plugin, + commandName, + "ecomenus.menus.${menu.id}.command", + true +) { + override fun onExecute(sender: Player, args: List) { + menu.menu.open(sender) + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/PositionedComponent.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/PositionedComponent.kt new file mode 100644 index 0000000..8c9ce44 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/PositionedComponent.kt @@ -0,0 +1,39 @@ +package com.willfp.ecomenus.components + +import com.willfp.eco.core.gui.GUIComponent +import com.willfp.eco.core.gui.menu.MenuBuilder +import com.willfp.eco.core.gui.menu.MenuLayer + +interface PositionedComponent : GUIComponent { + val row: Int + val column: Int + + val isEnabled: Boolean + get() = true + + val rowSize: Int + get() = 1 + val columnSize: Int + get() = 1 + + override fun getRows() = rowSize + override fun getColumns() = columnSize +} + +fun MenuBuilder.addComponent( + component: PositionedComponent +) = if (component.isEnabled) addComponent( + component.row, + component.column, + component +) else this + +fun MenuBuilder.addComponent( + layer: MenuLayer, + component: PositionedComponent +) = if (component.isEnabled) addComponent( + layer, + component.row, + component.column, + component +) else this diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/BackButton.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/BackButton.kt new file mode 100644 index 0000000..2ae721e --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/BackButton.kt @@ -0,0 +1,32 @@ +package com.willfp.ecomenus.components.impl + +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.gui.menu.Menu +import com.willfp.eco.core.gui.onLeftClick +import com.willfp.eco.core.gui.slot +import com.willfp.eco.core.items.Items +import com.willfp.eco.core.items.builder.ItemStackBuilder +import com.willfp.ecomenus.components.PositionedComponent +import org.bukkit.entity.Player + +class BackButton( + config: Config, + goBack: (Player, Menu) -> Unit +) : PositionedComponent { + private val slot = slot( + ItemStackBuilder(Items.lookup(config.getString("item"))) + .setDisplayName(config.getFormattedString("name")) + .build() + ) { + onLeftClick { _, event, _, menu -> + goBack(event.whoClicked as Player, menu) + } + } + + override val row: Int = config.getInt("location.row") + override val column: Int = config.getInt("location.column") + + override val isEnabled = config.getBool("enabled") + + override fun getSlotAt(row: Int, column: Int) = slot +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/CloseButton.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/CloseButton.kt new file mode 100644 index 0000000..0185d60 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/components/impl/CloseButton.kt @@ -0,0 +1,26 @@ +package com.willfp.ecomenus.components.impl + +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.gui.slot +import com.willfp.eco.core.items.Items +import com.willfp.eco.core.items.builder.ItemStackBuilder +import com.willfp.ecomenus.components.PositionedComponent + +class CloseButton( + config: Config +) : PositionedComponent { + private val slot = slot( + ItemStackBuilder(Items.lookup(config.getString("item"))) + .setDisplayName(config.getFormattedString("name")) + .build() + ) { + onLeftClick { event, _ -> event.whoClicked.closeInventory() } + } + + override val row: Int = config.getInt("location.row") + override val column: Int = config.getInt("location.column") + + override val isEnabled = config.getBool("enabled") + + override fun getSlotAt(row: Int, column: Int) = slot +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/ConfigCategory.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/ConfigCategory.kt new file mode 100644 index 0000000..46a3f2e --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/ConfigCategory.kt @@ -0,0 +1,58 @@ +package com.willfp.ecomenus.config + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.config.readConfig +import java.util.zip.ZipFile + +abstract class ConfigCategory( + val directory: String +) { + abstract fun clear(plugin: EcoPlugin) + + abstract fun acceptConfig(plugin: EcoPlugin, id: String, config: Config) + + internal fun reload(plugin: EcoPlugin) { + this.clear(plugin) + + for (config in this.fetchConfigs(plugin)) { + this.acceptConfig(plugin, config.id, config.config) + } + } + + internal fun copyConfigs(plugin: EcoPlugin) { + val folder = plugin.dataFolder.resolve(this.directory) + if (!folder.exists()) { + getDefaultConfigNames(plugin).forEach { configName -> + FoundConfig(configName, this.directory, plugin).copy() + } + } + } + + private fun getDefaultConfigNames(plugin: EcoPlugin): Collection { + val files = mutableListOf() + + try { + ZipFile(plugin.file).use { zipFile -> + zipFile.entries().asSequence() + .filter { it.name.startsWith("${this.directory}/") } + .mapTo(files) { it.name.removePrefix("${this.directory}/") } + } + } catch (_: Exception) { + // Sometimes, ZipFile likes to completely fail. No idea why, but here's the 'solution'! + } + + return files.filter { it.endsWith(".yml") }.map { it.removeSuffix(".yml") } + } + + private fun fetchConfigs(plugin: EcoPlugin): Set { + return plugin.dataFolder.resolve(directory) + .walk() + .filter { it.isFile && it.name.endsWith(".yml") && it.nameWithoutExtension != "_example" } + .map { file -> + val id = file.nameWithoutExtension + val config = file.readConfig() + IdentifiedConfig(config, id) + }.toSet() + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/FoundConfig.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/FoundConfig.kt new file mode 100644 index 0000000..6e65da4 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/FoundConfig.kt @@ -0,0 +1,27 @@ +package com.willfp.ecomenus.config + +import com.willfp.eco.core.EcoPlugin +import java.io.FileOutputStream + +class FoundConfig( + name: String, + directory: String, + private val plugin: EcoPlugin +) { + private val source = plugin::class.java.classLoader + private val resourcePath = "$directory/$name.yml" + + fun copy() { + val inputStream = source.getResourceAsStream(resourcePath) ?: return + val outFile = plugin.dataFolder.resolve(resourcePath) + + if (!outFile.exists()) { + outFile.parentFile.mkdirs() + FileOutputStream(outFile).use { outStream -> + inputStream.copyTo(outStream) + } + } + + inputStream.close() + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/IdentifiedConfig.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/IdentifiedConfig.kt new file mode 100644 index 0000000..791ad1c --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/config/IdentifiedConfig.kt @@ -0,0 +1,8 @@ +package com.willfp.ecomenus.config + +import com.willfp.eco.core.config.interfaces.Config + +internal data class IdentifiedConfig( + val config: Config, + val id: String +) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenu.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenu.kt new file mode 100644 index 0000000..e609ede --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenu.kt @@ -0,0 +1,22 @@ +package com.willfp.ecomenus.menus + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.registry.KRegistrable +import com.willfp.ecomenus.commands.DynamicMenuCommand + +class EcoMenu( + private val plugin: EcoPlugin, + override val id: String, + val config: Config +) : KRegistrable { + val menu = buildMenu(plugin, config) + + private val commandName = config.getStringOrNull("command") + + init { + if (commandName != null) { + DynamicMenuCommand(plugin, this, commandName).register() + } + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenus.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenus.kt new file mode 100644 index 0000000..0225acc --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/EcoMenus.kt @@ -0,0 +1,26 @@ +package com.willfp.ecomenus.menus + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.registry.Registry +import com.willfp.ecomenus.config.ConfigCategory + +object EcoMenus : ConfigCategory("menus") { + private val registry = Registry() + + override fun clear(plugin: EcoPlugin) { + registry.clear() + } + + override fun acceptConfig(plugin: EcoPlugin, id: String, config: Config) { + registry.register(EcoMenu(plugin, id, config)) + } + + fun values(): Collection { + return registry.values() + } + + operator fun get(id: String): EcoMenu? { + return registry.get(id) + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/Menu.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/Menu.kt new file mode 100644 index 0000000..8f42689 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecomenus/menus/Menu.kt @@ -0,0 +1,69 @@ +package com.willfp.ecomenus.menus + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.gui.menu +import com.willfp.eco.core.gui.menu.Menu +import com.willfp.eco.core.gui.slot.ConfigSlot +import com.willfp.eco.core.gui.slot.FillerMask +import com.willfp.eco.core.gui.slot.MaskItems +import com.willfp.ecomenus.components.addComponent +import com.willfp.ecomenus.components.impl.BackButton +import com.willfp.ecomenus.components.impl.CloseButton +import com.willfp.ecomponent.menuStateVar +import org.bukkit.entity.Player +import java.util.Stack + +val Menu.previousMenus by menuStateVar>("previous-menu", Stack()) + +fun Stack.popOrNull(): T? = + if (this.empty()) null else this.pop() + +fun Menu.open( + player: Player, + from: Menu? = null +) { + this.open(player) + if (from != null) { + this.previousMenus[player] += from + } +} + +fun Menu.close(player: Player) = + this.previousMenus[player].popOrNull()?.open(player) ?: player.closeInventory() + +fun buildMenu(plugin: EcoPlugin, config: Config): Menu { + val mask = FillerMask( + MaskItems.fromItemNames(plugin.configYml.getStrings("mask.materials")), + *plugin.configYml.getStrings("mask.pattern").toTypedArray() + ) + + return menu(mask.rows) { + title = config.getFormattedString("title") + + setMask(mask) + + addComponent( + CloseButton( + plugin.configYml.getSubsection("stats-gui.close") + ) + ) + + addComponent( + BackButton( + plugin.configYml.getSubsection("stats-gui.back") + ) { player, menu -> + menu.close(player) + } + ) + + // TODO: Implement Slots + for (test in plugin.configYml.getSubsections("stats-gui.custom-slots")) { + setSlot( + test.getInt("row"), + test.getInt("column"), + ConfigSlot(test) + ) + } + } +} diff --git a/eco-core/core-plugin/src/main/resources/eco.yml b/eco-core/core-plugin/src/main/resources/eco.yml index 7dbb379..e0d6844 100644 --- a/eco-core/core-plugin/src/main/resources/eco.yml +++ b/eco-core/core-plugin/src/main/resources/eco.yml @@ -1,5 +1,5 @@ options: bstats-id: 0 resource-id: 0 - color: "&a" + color: "#FCEDDA" uses-reflective-reload: false diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml index 5a7e91a..1022608 100644 --- a/eco-core/core-plugin/src/main/resources/lang.yml +++ b/eco-core/core-plugin/src/main/resources/lang.yml @@ -1,5 +1,5 @@ messages: - prefix: "&a&lEcoMenus &f» " + prefix: "&#FCEDDA&lEcoMenus &f» " no-permission: "&cYou don't have permission to do this!" not-player: "&cThis command must be run by a player" invalid-command: "&cUnknown subcommand!" diff --git a/eco-core/core-plugin/src/main/resources/menus/_example.yml b/eco-core/core-plugin/src/main/resources/menus/_example.yml new file mode 100644 index 0000000..ea27c92 --- /dev/null +++ b/eco-core/core-plugin/src/main/resources/menus/_example.yml @@ -0,0 +1,40 @@ +# The title of the GUI +title: "Example GUI" + +command: examplemenu # (Optional) The command to open the GUI, if not set, there will be no command. + +mask: + # The way the mask works is by having a list of materials + # And then a pattern to use those materials. + + # The size of the GUI is the size of the mask. + + # The pattern is the rows in the GUI + # Each line must be 9 long, and the amount of rows should be the amount of rows in the GUI + # A zero represents nothing + # A 1 represents the first material + # A 2 represents the second material + # And so on, you can add up to 9. + + materials: + - gray_stained_glass_pane + - black_stained_glass_pane + pattern: + - "211101112" + - "211111112" + - "210000012" + - "210010012" + - "211111112" + - "211101112" + +# Options for the close item +close: + item: barrier + name: "&cClose" + enabled: false + location: + row: 6 + column: 5 + +# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots +custom-slots: [ ]