mirror of
https://github.com/Auxilor/EcoMenus.git
synced 2025-12-30 04:19:23 +00:00
Initial project outline
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ConfigCategory>(
|
||||
EcoMenus
|
||||
)
|
||||
|
||||
override fun handleEnable() {
|
||||
for (category in categories) {
|
||||
category.copyConfigs(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleReload() {
|
||||
for (category in categories) {
|
||||
category.reload(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>) {
|
||||
menu.menu.open(sender)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<String> {
|
||||
val files = mutableListOf<String>()
|
||||
|
||||
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<IdentifiedConfig> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<EcoMenu>()
|
||||
|
||||
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<EcoMenu> {
|
||||
return registry.values()
|
||||
}
|
||||
|
||||
operator fun get(id: String): EcoMenu? {
|
||||
return registry.get(id)
|
||||
}
|
||||
}
|
||||
@@ -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<Stack<Menu>>("previous-menu", Stack())
|
||||
|
||||
fun <T> Stack<T>.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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
options:
|
||||
bstats-id: 0
|
||||
resource-id: 0
|
||||
color: "&a"
|
||||
color: "#FCEDDA"
|
||||
uses-reflective-reload: false
|
||||
|
||||
@@ -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!"
|
||||
|
||||
40
eco-core/core-plugin/src/main/resources/menus/_example.yml
Normal file
40
eco-core/core-plugin/src/main/resources/menus/_example.yml
Normal file
@@ -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: [ ]
|
||||
Reference in New Issue
Block a user