diff --git a/build.gradle b/build.gradle index 00ed2b8..ec2925c 100644 --- a/build.gradle +++ b/build.gradle @@ -49,7 +49,7 @@ allprojects { dependencies { compileOnly 'com.willfp:eco:6.46.0' implementation 'com.willfp:libreforge:3.129.1' - implementation 'com.willfp:ecomponent:1.0.0' + implementation 'com.willfp:ecomponent:1.3.0' implementation 'org.joml:joml:1.10.4' compileOnly 'org.jetbrains:annotations:23.0.0' diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/EcoJobsPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/EcoJobsPlugin.kt index 94b33eb..bce3839 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/EcoJobsPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/EcoJobsPlugin.kt @@ -2,7 +2,9 @@ package com.willfp.ecojobs import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.placeholder.PlayerPlaceholder -import com.willfp.eco.util.toSingletonList +import com.willfp.ecojobs.api.activeJobs +import com.willfp.ecojobs.api.getJobLevel +import com.willfp.ecojobs.api.jobLimit import com.willfp.ecojobs.commands.CommandEcojobs import com.willfp.ecojobs.commands.CommandJobs import com.willfp.ecojobs.jobs.JobLevelListener @@ -10,16 +12,15 @@ import com.willfp.ecojobs.jobs.JobTriggerXPGainListener import com.willfp.ecojobs.jobs.Jobs import com.willfp.ecojobs.jobs.PriceHandler import com.willfp.ecojobs.jobs.ResetOnQuitListener -import com.willfp.ecojobs.jobs.activeJob -import com.willfp.ecojobs.jobs.activeJobLevel -import com.willfp.ecojobs.jobs.getJobLevel import com.willfp.libreforge.LibReforgePlugin import org.bukkit.event.Listener class EcoJobsPlugin : LibReforgePlugin() { init { instance = this - registerHolderProvider { it.activeJobLevel?.toSingletonList() ?: emptyList() } + registerHolderProvider { player -> + player.activeJobs.map { it.getLevel(player.getJobLevel(it)) } + } } override fun handleEnableAdditional() { @@ -27,18 +28,13 @@ class EcoJobsPlugin : LibReforgePlugin() { PlayerPlaceholder( this, - "job" - ) { it.activeJob?.name ?: "" }.register() + "limit" + ) { it.jobLimit.toString() }.register() PlayerPlaceholder( this, - "job_level" - ) { it.activeJobLevel?.level?.toString() ?: "" }.register() - - PlayerPlaceholder( - this, - "job_id" - ) { it.activeJob?.id ?: "" }.register() + "in_jobs" + ) { it.activeJobs.size.toString() }.register() PlayerPlaceholder( this, diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/commands/CommandJoin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/commands/CommandJoin.kt index bff59dc..afe033f 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/commands/CommandJoin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/commands/CommandJoin.kt @@ -36,7 +36,7 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma } if (!player.canJoinJob(job)) { - player.sendMessage(plugin.langYml.getMessage("leave-current-job")) + player.sendMessage(plugin.langYml.getMessage("cannot-join-job")) return } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/Job.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/Job.kt index 063c8d9..43e18d4 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/Job.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/Job.kt @@ -26,6 +26,7 @@ import com.willfp.ecojobs.api.getJobLevel import com.willfp.ecojobs.api.getJobProgress import com.willfp.ecojobs.api.getJobXP import com.willfp.ecojobs.api.getJobXPRequired +import com.willfp.ecojobs.api.hasJobActive import com.willfp.ecojobs.api.jobLimit import com.willfp.libreforge.conditions.Conditions import com.willfp.libreforge.conditions.ConfiguredCondition @@ -305,7 +306,9 @@ class Job( ).addLoreLines { injectPlaceholdersInto( plugin.configYml.getStrings("gui.job-icon.lore"), player - ) + if (player.canJoinJob(this)) { + ) + if (player.hasJobActive(this)) { + plugin.configYml.getStrings("gui.job-icon.active-lore") + } else if (player.canJoinJob(this)) { plugin.configYml.getStrings("gui.job-icon.join-lore") } else if (player.activeJobs.size == player.jobLimit) { plugin.configYml.getStrings("gui.job-icon.too-many-jobs-lore") diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/JobsGUI.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/JobsGUI.kt index fe2e3a3..1eae99e 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/JobsGUI.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecojobs/jobs/JobsGUI.kt @@ -4,19 +4,28 @@ import com.willfp.eco.core.config.updating.ConfigUpdater import com.willfp.eco.core.gui.menu import com.willfp.eco.core.gui.menu.Menu import com.willfp.eco.core.gui.onLeftClick +import com.willfp.eco.core.gui.onRightClick +import com.willfp.eco.core.gui.page.PageChanger import com.willfp.eco.core.gui.slot 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.eco.core.items.Items import com.willfp.eco.core.items.builder.ItemStackBuilder +import com.willfp.eco.core.items.builder.SkullBuilder +import com.willfp.eco.util.formatEco import com.willfp.ecojobs.EcoJobsPlugin +import com.willfp.ecojobs.api.activeJobs +import com.willfp.ecojobs.api.canJoinJob import com.willfp.ecojobs.api.getJobLevel +import com.willfp.ecojobs.api.hasJobActive +import com.willfp.ecojobs.api.joinJob import com.willfp.ecojobs.jobs.Jobs.unlockedJobs import org.bukkit.Material import org.bukkit.Sound import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.SkullMeta import kotlin.math.ceil import kotlin.math.max import kotlin.math.min @@ -24,17 +33,6 @@ import kotlin.math.min object JobsGUI { private lateinit var menu: Menu private val jobAreaSlots = mutableListOf>() - private const val pageKey = "page" - - private fun getPage(menu: Menu, player: Player): Int { - val pages = ceil(Jobs.values() - .filter { player.getJobLevel(it) > 0 } - .size.toDouble() / jobAreaSlots.size).toInt() - - val page = menu.getState(player, pageKey) ?: 1 - - return max(min(pages, page + 1), 1) - } @JvmStatic @ConfigUpdater @@ -55,18 +53,8 @@ object JobsGUI { } private fun buildMenu(plugin: EcoJobsPlugin): Menu { - val jobInfoItemBuilder = { player: Player, _: Menu -> - val job = player.activeJob - - job?.getJobInfoIcon(player) - ?: ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.job-info.no-active.item"))) - .setDisplayName(plugin.configYml.getFormattedString("gui.job-info.no-active.name")) - .addLoreLines(plugin.configYml.getFormattedStrings("gui.job-info.no-active.lore")) - .build() - } - val jobIconBuilder = { player: Player, menu: Menu, index: Int -> - val page = getPage(menu, player) + val page = menu.getPage(player) val unlockedJobs = player.unlockedJobs @@ -87,13 +75,46 @@ object JobsGUI { ) setSlot( - plugin.configYml.getInt("gui.job-info.row"), - plugin.configYml.getInt("gui.job-info.column"), - slot(jobInfoItemBuilder) { - onLeftClick { event, _, _ -> - val player = event.whoClicked as Player - player.activeJob?.levelGUI?.open(player) + plugin.configYml.getInt("gui.player-info.row"), + plugin.configYml.getInt("gui.player-info.column"), + slot { player, _ -> + val skullBuilder = SkullBuilder() + .setDisplayName( + plugin.configYml.getString("gui.player-info.name") + .replace("%player%", player.displayName) + .formatEco(player, true) + ) + + if (player.activeJobs.isEmpty()) { + skullBuilder.addLoreLines( + plugin.configYml.getStrings("gui.player-info.no-jobs") + .formatEco(player, true) + ) + } else { + skullBuilder.addLoreLines( + plugin.configYml.getStrings("gui.player-info.has-jobs") + .flatMap { + if (it == "%jobs%") { + player.activeJobs.flatMap { job -> + job.injectPlaceholdersInto( + plugin.configYml.getStrings("gui.player-info.job-line"), + player + ) + } + } else { + listOf(it) + } + } + .formatEco(player, true) + ) } + + val skull = skullBuilder.build() + + val meta = skull.itemMeta as SkullMeta + meta.owningPlayer = player + skull.itemMeta = meta + skull } ) @@ -101,10 +122,8 @@ object JobsGUI { val (row, column) = pair setSlot(row, column, slot({ p, m -> jobIconBuilder(p, m, index) }) { - onLeftClick { event, _, _ -> - val player = event.whoClicked as Player - - val page = getPage(menu, player) + onLeftClick { player, _, _, menu -> + val page = menu.getPage(player) val unlockedJobs = player.unlockedJobs @@ -112,10 +131,22 @@ object JobsGUI { val job = unlockedJobs.getOrNull(pagedIndex) ?: return@onLeftClick - if (player.activeJob == null) { - player.activeJob = job + if (player.hasJobActive(job)) { + job.levelGUI.open(player) } else { - player.sendMessage(plugin.langYml.getMessage("leave-current-job")) + if (player.canJoinJob(job)) { + player.joinJob(job) + + if (player.hasJobActive(job)) { + player.sendMessage( + plugin.langYml.getMessage("joined-job") + .replace("%job%", job.name) + ) + } + } else { + player.sendMessage(plugin.langYml.getMessage("cannot-join-job")) + return@onLeftClick + } } player.playSound( @@ -125,52 +156,58 @@ object JobsGUI { plugin.configYml.getDouble("gui.job-icon.click.pitch").toFloat() ) } + + onRightClick { player, _, _, menu -> + val page = menu.getPage(player) + + val unlockedJobs = player.unlockedJobs + + val pagedIndex = ((page - 1) * jobAreaSlots.size) + index + + val job = unlockedJobs.getOrNull(pagedIndex) ?: return@onRightClick + + if (player.hasJobActive(job)) { + job.leaveGUI.open(player) + + player.playSound( + player.location, + Sound.valueOf(plugin.configYml.getString("gui.job-icon.click.sound").uppercase()), + 1f, + plugin.configYml.getDouble("gui.job-icon.click.pitch").toFloat() + ) + } + } }) } - setSlot( + addComponent( plugin.configYml.getInt("gui.prev-page.location.row"), plugin.configYml.getInt("gui.prev-page.location.column"), - slot( + PageChanger( ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.prev-page.item"))) .setDisplayName(plugin.configYml.getString("gui.prev-page.name")) - .build() - ) { - onLeftClick { event, _, menu -> - val player = event.whoClicked as Player - val page = getPage(menu, player) - - val newPage = max(1, page - 1) - - menu.setState(player, pageKey, newPage) - } - } + .build(), + PageChanger.Direction.BACKWARDS + ) ) - setSlot( + addComponent( plugin.configYml.getInt("gui.next-page.location.row"), plugin.configYml.getInt("gui.next-page.location.column"), - slot( + PageChanger( ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.next-page.item"))) .setDisplayName(plugin.configYml.getString("gui.next-page.name")) - .build() - ) { - onLeftClick { event, _, menu -> - val player = event.whoClicked as Player - - val pages = ceil(Jobs.values() - .filter { player.getJobLevel(it) > 0 } - .size.toDouble() / jobAreaSlots.size).toInt() - - val page = getPage(menu, player) - - val newPage = min(pages, page + 1) - - menu.setState(player, pageKey, newPage) - } - } + .build(), + PageChanger.Direction.FORWARDS + ) ) + maxPages { player -> + ceil(Jobs.values() + .filter { player.getJobLevel(it) > 0 } + .size.toDouble() / jobAreaSlots.size).toInt() + } + setSlot(plugin.configYml.getInt("gui.close.location.row"), plugin.configYml.getInt("gui.close.location.column"), slot( @@ -182,19 +219,6 @@ object JobsGUI { } ) - setSlot(plugin.configYml.getInt("gui.deactivate-job.location.row"), - plugin.configYml.getInt("gui.deactivate-job.location.column"), - slot( - ItemStackBuilder(Items.lookup(plugin.configYml.getString("gui.deactivate-job.item"))) - .setDisplayName(plugin.configYml.getString("gui.deactivate-job.name")) - .build() - ) { - onLeftClick { player, _, _, _ -> - player.activeJob?.leaveGUI?.open(player) - } - } - ) - for (config in plugin.configYml.getSubsections("gui.custom-slots")) { setSlot( config.getInt("row"), diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml index e1152d4..e28697d 100644 --- a/eco-core/core-plugin/src/main/resources/config.yml +++ b/eco-core/core-plugin/src/main/resources/config.yml @@ -24,49 +24,44 @@ gui: materials: - black_stained_glass_pane pattern: + - "111101111" - "111111111" - - "101000001" - - "111000001" - - "101000001" - - "111111111" - - "111100011" + - "100000001" + - "100000001" + - "100000001" + - "111101111" job-area: top-left: - row: 2 - column: 4 + row: 3 + column: 2 bottom-right: - row: 4 + row: 5 column: 8 - job-info: + player-info: row: 2 column: 2 - no-active: - name: "&cNo Active Job" - lore: - - "" - - "&cYou do not currently have a job active" - - "&fPick one from the options below!" - - "" - item: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19 + name: "%player%&f's Jobs:" - # %join_price% and %leave_price% are also available as placeholders + no-jobs: + - "" + - "&cYou do not currently have a job active" + - "&fPick one from the options below!" + - "" + - "&fYou can have up to &a%ecojobs_limit% &fjobs at once" + - "" - active: - name: "%job% &fLvl. &a%level%" - lore: - - "%description%" - - "&f" - - "&fJob Rewards:" - - "%effects%" - - "" - - "&fProgress:" - - "&8» &e%percentage_progress%%" - - "&8» &e%current_xp%&8/&7%required_xp% &fXP" - - "" - - "&eClick to view Level Progression!" + has-jobs: + - "" + - "%jobs%" + - "" + - "&fJob slots in use: &a%ecojobs_in_jobs%&r/&a%ecojobs_limit%" + - "" + + job-line: + - " %job% &fLvl. &a%level%" job-icon: name: "%job% &fLvl. &a%level%" @@ -80,9 +75,12 @@ gui: - "&8» &e%percentage_progress%%" - "&8» &e%current_xp%&8/&7%required_xp% &fXP" + # %join_price% and %leave_price% are also available as placeholders + active-lore: - "" - - "&cYou've already joined this job!" + - "&eClick to view Level Progression!" + - "&eRight-click to leave this job!" too-many-jobs-lore: - "" @@ -101,28 +99,21 @@ gui: name: "&fPrevious Page" location: row: 6 - column: 5 + column: 4 next-page: item: arrow name: "&fNext Page" location: row: 6 - column: 7 + column: 6 close: item: barrier name: "&cClose" location: row: 6 - column: 6 - - deactivate-job: - item: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTRiZDlhNDViOTY4MWNlYTViMjhjNzBmNzVhNjk1NmIxZjU5NGZlYzg0MGI5NjA3Nzk4ZmIxZTcwNzc2NDQzMCJ9fX0= - name: "&cDeactivate Job" - location: - row: 4 - column: 2 + column: 5 # Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots custom-slots: [ ] diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml index 9d1007e..3844f7e 100644 --- a/eco-core/core-plugin/src/main/resources/lang.yml +++ b/eco-core/core-plugin/src/main/resources/lang.yml @@ -33,7 +33,7 @@ messages: joined-job: "&fYou have joined the %job%&f job!" left-job: "&fYou have left the %job%&f job!" job-already-joined: "&cYou already have this job!" - leave-current-job: "&cYou must leave your current job before joining a new one!" + cannot-join-job: "&cYou are already in too many jobs, please leave one!" cant-leave-job: "&cYou can't leave the %job%&f job!" dont-have-job: "&cYou don't have this job unlocked!" not-in-job: "&cYou are not in this job!"