9
0
mirror of https://github.com/Auxilor/EcoJobs.git synced 2025-12-20 07:29:20 +00:00

Compare commits

...

35 Commits

Author SHA1 Message Date
Auxilor
935e9a7937 libreforge-updater 2023-02-15 20:57:47 +00:00
Auxilor
04c2571d0f Added %ecojobs_<id>_active% placeholder 2023-02-15 18:48:47 +00:00
Auxilor
bd1b1aaa75 Cleaned up default config 2023-02-15 18:47:26 +00:00
Auxilor
f942ebd9ed Updated to 2.0.0 2023-02-15 18:43:32 +00:00
Auxilor
dfbc77cd0a Updated GUI 2023-02-15 18:43:15 +00:00
Auxilor
760c3ce707 Updated to 2.0 with multiple jobs support (todo: GUI) 2023-02-15 18:01:43 +00:00
Auxilor
b4db83feb1 libreforge-updater 2023-02-12 16:54:39 +00:00
Auxilor
31980faf05 libreforge-updater 2023-02-09 14:11:37 +00:00
Auxilor
91645c13ac Added JobEvent 2023-02-08 17:24:41 +00:00
Auxilor
420279fefa libreforge-updater 2023-02-07 14:45:38 +00:00
Auxilor
e5d4cfb4ac libreforge-updater 2023-02-04 15:35:40 +00:00
Auxilor
ee3a4110ee libreforge-updater 2023-01-24 10:08:34 +00:00
Auxilor
c8ae5bd4be libreforge-updater 2023-01-17 16:47:31 +00:00
Auxilor
83ee1c2c1e libreforge-updater 2023-01-13 18:07:37 +00:00
Auxilor
f79cb8192a libreforge-updater 2023-01-07 12:18:26 +00:00
Auxilor
7d8f79a81b libreforge-updater 2023-01-02 15:59:08 +00:00
Auxilor
3571d7ddf3 libreforge-updater 2022-12-26 14:00:32 +01:00
Auxilor
ed33219f97 libreforge-updater 2022-12-20 15:16:12 +00:00
Auxilor
78cef09786 libreforge-updater 2022-12-12 14:00:27 +00:00
Auxilor
2a72f7d6ce libreforge-updater 2022-12-09 17:00:49 +00:00
Auxilor
762a871354 libreforge-updater 2022-12-05 10:49:59 +00:00
Auxilor
b101e23a86 libreforge-updater 2022-11-30 17:37:48 +00:00
Auxilor
07e1cb7797 libreforge-updater 2022-11-27 21:43:56 +00:00
Auxilor
409a84aea8 libreforge-updater 2022-11-26 19:19:52 +00:00
Auxilor
886b2e0c06 libreforge-updater 2022-11-24 14:29:42 +00:00
Auxilor
0ff5dcf670 libreforge-updater 2022-11-23 17:24:43 +00:00
Auxilor
1b93969d3b libreforge-updater 2022-11-21 16:02:22 +00:00
Auxilor
af5f5cfba6 Updated to 1.26.2 2022-11-21 12:59:11 +00:00
Auxilor
2c726fd9ac Fixed jumberjack 2022-11-21 12:59:03 +00:00
Auxilor
8dbe453bc5 Fix 2022-11-21 12:57:23 +00:00
Auxilor
768d2218d0 Fix 2022-11-21 11:45:20 +00:00
Auxilor
e212762951 Fix 2022-11-21 11:45:05 +00:00
Auxilor
c5d7e07d49 Updated to 1.26.1 2022-11-21 11:41:54 +00:00
Auxilor
88d118cdd7 Added /jobs <job> 2022-11-21 11:41:46 +00:00
Auxilor
b08616b01e libreforge-updater 2022-11-17 08:37:53 +00:00
26 changed files with 633 additions and 597 deletions

View File

@@ -47,9 +47,9 @@ allprojects {
}
dependencies {
compileOnly 'com.willfp:eco:6.45.0'
implementation 'com.willfp:libreforge:3.119.0'
implementation 'com.willfp:ecomponent:1.0.0'
compileOnly 'com.willfp:eco:6.46.0'
implementation 'com.willfp:libreforge:3.129.2'
implementation 'com.willfp:ecomponent:1.3.0'
implementation 'org.joml:joml:1.10.4'
compileOnly 'org.jetbrains:annotations:23.0.0'

View File

@@ -1,36 +0,0 @@
package com.willfp.ecojobs
import com.willfp.ecojobs.api.EcoJobsAPI
import com.willfp.ecojobs.jobs.Job
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.getJobLevel
import com.willfp.ecojobs.jobs.getJobProgress
import com.willfp.ecojobs.jobs.getJobXP
import com.willfp.ecojobs.jobs.getJobXPRequired
import com.willfp.ecojobs.jobs.giveJobExperience
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
internal object EcoJobsAPIImpl : EcoJobsAPI {
override fun hasJob(player: OfflinePlayer, job: Job) = player.hasJob(job)
override fun getActiveJob(player: OfflinePlayer): Job? = player.activeJob
override fun getJobLevel(player: OfflinePlayer, job: Job) = player.getJobLevel(job)
override fun giveJobExperience(player: Player, job: Job, amount: Double) =
player.giveJobExperience(job, amount)
override fun giveJobExperience(player: Player, job: Job, amount: Double, applyMultipliers: Boolean) =
player.giveJobExperience(job, amount, noMultiply = !applyMultipliers)
override fun getJobProgress(player: OfflinePlayer, job: Job) =
player.getJobProgress(job)
override fun getJobXPRequired(player: OfflinePlayer, job: Job) =
player.getJobXPRequired(job)
override fun getJobXP(player: OfflinePlayer, job: Job) =
player.getJobXP(job)
}

View File

@@ -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,

View File

@@ -1,117 +1,192 @@
@file:JvmName("EcoJobsAPI")
package com.willfp.ecojobs.api
import com.willfp.ecojobs.EcoJobsAPIImpl
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
import com.willfp.ecojobs.jobs.Job
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.getNumericalPermission
import com.willfp.ecojobs.jobs.jobExperienceMultiplier
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import kotlin.math.abs
interface EcoJobsAPI {
/**
* Get if a player has a job.
*
* @param player The player.
* @param job The job.
* @return If the player has the job unlocked.
*/
fun hasJob(
player: OfflinePlayer,
job: Job
): Boolean
private val plugin = EcoJobsPlugin.instance
/**
* Get a player's active job.
*
* @param player The player.
* @return The active job.
*/
fun getActiveJob(
player: OfflinePlayer
): Job?
/*
/**
* Get a player's level of a certain job.
*
* @param player The player.
* @param job The job.
* @return The level.
*/
fun getJobLevel(
player: OfflinePlayer,
job: Job
): Int
The old key is around for backwards compatibility with 1.x.x.
/**
* Give job experience to a player.
*
* @param player The player.
* @param job The job.
* @param amount The amount of experience to give.
*/
fun giveJobExperience(
player: Player,
job: Job,
amount: Double
)
/**
* Give job experience to a player.
*
* @param player The player.
* @param job The job.
* @param amount The amount of experience to give.
* @param applyMultipliers If multipliers should be applied.
*/
fun giveJobExperience(
player: Player,
job: Job,
amount: Double,
applyMultipliers: Boolean
)
private val legacyActiveJobKey: PersistentDataKey<String> = PersistentDataKey(
plugin.namespacedKeyFactory.create("active_job"), PersistentDataKeyType.STRING, ""
)
/**
* Get progress to next level between 0 and 1, where 0 is none and 1 is complete.
*
* @param player The player.
* @param job The job.
* @return The progress.
*/
fun getJobProgress(
player: OfflinePlayer,
job: Job
): Double
private val activeJobsKey: PersistentDataKey<List<String>> = PersistentDataKey(
plugin.namespacedKeyFactory.create("active_jobs"), PersistentDataKeyType.STRING_LIST, listOf()
)
/**
* Get the experience required to advance to the next level.
*
* @param player The player.
* @param job The job.
* @return The experience required.
/**
* The job limit.
*/
fun getJobXPRequired(
player: OfflinePlayer,
job: Job
): Int
val Player.jobLimit: Int
get() {
return this.getNumericalPermission("ecojobs.limit", plugin.configYml.getDouble("jobs.limit")).toInt()
}
/**
* Get experience to the next level.
*
* @param player The player.
* @param job The job.
* @return The experience.
/**
* If a player can join a job.
*/
fun getJobXP(
player: OfflinePlayer,
job: Job
): Double
fun Player.canJoinJob(job: Job): Boolean {
return this.activeJobs.size < this.jobLimit && job !in this.activeJobs && this.hasJob(job)
}
companion object {
/**
* Get the instance of the API.
*
* @return The API.
/**
* Get if a job is unlocked.
*/
@JvmStatic
val instance: EcoJobsAPI
get() = EcoJobsAPIImpl
fun OfflinePlayer.hasJob(job: Job) = this.getJobLevel(job) > 0
/**
* Get if a player has a job active.
*/
fun OfflinePlayer.hasJobActive(job: Job) = job in this.activeJobs
/**
* Get a player's active jobs.
*/
val OfflinePlayer.activeJobs: Collection<Job>
get() {
if (this.profile.read(legacyActiveJobKey).isNotBlank()) {
this.profile.write(activeJobsKey, listOf(this.profile.read(legacyActiveJobKey)))
this.profile.write(legacyActiveJobKey, "")
}
return this.profile.read(activeJobsKey).mapNotNull { Jobs.getByID(it) }
}
/**
* Join a job.
*/
fun OfflinePlayer.joinJob(job: Job) {
val event = PlayerJobJoinEvent(this, job)
Bukkit.getPluginManager().callEvent(event)
if (!event.isCancelled) {
this.profile.write(activeJobsKey, this.activeJobs.plus(job).map { it.id })
}
}
/**
* Leave a job.
*/
fun OfflinePlayer.leaveJob(job: Job) {
if (job !in this.activeJobs) {
return
}
val event = PlayerJobLeaveEvent(this, job)
Bukkit.getPluginManager().callEvent(event)
if (!event.isCancelled) {
this.forceLeaveJob(job)
}
}
/**
* Leave a job without checking.
*/
fun OfflinePlayer.forceLeaveJob(job: Job) {
this.profile.write(activeJobsKey, this.activeJobs.minus(job).map { it.id })
}
/**
* Get the level of a certain job.
*/
fun OfflinePlayer.getJobLevel(job: Job) = this.profile.read(job.levelKey)
/**
* Set the level of a certain job.
*/
fun OfflinePlayer.setJobLevel(job: Job, level: Int) = this.profile.write(job.levelKey, level)
/**
* Get current job experience.
*/
fun OfflinePlayer.getJobXP(job: Job) = this.profile.read(job.xpKey)
/**
* Set current job experience.
*/
fun OfflinePlayer.setJobXP(job: Job, xp: Double) = this.profile.write(job.xpKey, xp)
/**
* Reset a job.
*/
fun OfflinePlayer.resetJob(job: Job) {
this.setJobLevel(job, 1)
this.setJobXP(job, 0.0)
}
/**
* Get the experience required to advance to the next level.
*/
fun OfflinePlayer.getJobXPRequired(job: Job) = job.getExpForLevel(this.getJobLevel(job) + 1)
/**
* Get progress to next level between 0 and 1, where 0 is none and 1 is complete.
*/
fun OfflinePlayer.getJobProgress(job: Job): Double {
val currentXP = this.getJobXP(job)
val requiredXP = job.getExpForLevel(this.getJobLevel(job) + 1)
return currentXP / requiredXP
}
/**
* Give job experience.
*/
@JvmOverloads
fun Player.giveJobExperience(job: Job, experience: Double, withMultipliers: Boolean = true) {
val exp = abs(
if (withMultipliers) experience * this.jobExperienceMultiplier
else experience
)
val gainEvent = PlayerJobExpGainEvent(this, job, exp, !withMultipliers)
Bukkit.getPluginManager().callEvent(gainEvent)
if (gainEvent.isCancelled) {
return
}
this.giveExactJobExperience(job, gainEvent.amount)
}
/**
* Give exact job experience, without calling PlayerJobExpGainEvent.
*/
fun Player.giveExactJobExperience(job: Job, experience: Double) {
val level = this.getJobLevel(job)
val progress = this.getJobXP(job) + experience
if (progress >= job.getExpForLevel(level + 1) && level + 1 <= job.maxLevel) {
val overshoot = progress - job.getExpForLevel(level + 1)
this.setJobXP(job, 0.0)
this.setJobLevel(job, level + 1)
val levelUpEvent = PlayerJobLevelUpEvent(this, job, level + 1)
Bukkit.getPluginManager().callEvent(levelUpEvent)
this.giveExactJobExperience(job, overshoot)
} else {
this.setJobXP(job, progress)
}
}

View File

@@ -0,0 +1,7 @@
package com.willfp.ecojobs.api.event
import com.willfp.ecojobs.jobs.Job
interface JobEvent {
val job: Job
}

View File

@@ -8,10 +8,10 @@ import org.bukkit.event.Cancellable
class PlayerJobExpGainEvent(
who: Player,
val job: Job,
override val job: Job,
var amount: Double,
val isMultiply: Boolean
) : PlayerEvent(who), Cancellable {
) : PlayerEvent(who), Cancellable, JobEvent {
private var cancelled = false
override fun setCancelled(cancel: Boolean) {

View File

@@ -8,9 +8,8 @@ import org.bukkit.event.HandlerList
class PlayerJobJoinEvent(
val player: OfflinePlayer,
val job: Job,
val oldJob: Job?
) : Event(), Cancellable {
override val job: Job
) : Event(), Cancellable, JobEvent {
private var cancelled = false
override fun isCancelled() = this.cancelled

View File

@@ -8,8 +8,8 @@ import org.bukkit.event.HandlerList
class PlayerJobLeaveEvent(
val player: OfflinePlayer,
val job: Job
) : Event(), Cancellable {
override val job: Job
) : Event(), Cancellable, JobEvent {
private var cancelled = false
override fun isCancelled() = this.cancelled

View File

@@ -7,9 +7,9 @@ import org.bukkit.event.HandlerList
class PlayerJobLevelUpEvent(
who: Player,
val job: Job,
override val job: Job,
val level: Int
) : PlayerEvent(who) {
) : PlayerEvent(who), JobEvent {
override fun getHandlers(): HandlerList {
return handlerList
}

View File

@@ -5,9 +5,9 @@ import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.eco.util.toNiceString
import com.willfp.ecojobs.api.giveExactJobExperience
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.giveExactJobExperience
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender

View File

@@ -2,9 +2,11 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.JobsGUI
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandJobs(plugin: EcoPlugin) : PluginCommand(plugin, "jobs", "ecojobs.command.jobs", true) {
init {
@@ -12,8 +14,44 @@ class CommandJobs(plugin: EcoPlugin) : PluginCommand(plugin, "jobs", "ecojobs.co
.addSubcommand(CommandLeave(plugin))
}
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
override fun onExecute(player: Player, args: List<String>) {
if (args.isEmpty()) {
JobsGUI.open(player)
return
}
val id = args[0].lowercase()
val job = Jobs.getByID(id)
if (job == null) {
player.sendMessage(plugin.langYml.getMessage("invalid-job"))
return
}
if (!player.hasJob(job)) {
player.sendMessage(plugin.langYml.getMessage("dont-have-job"))
return
}
job.levelGUI.open(player)
}
override fun tabComplete(player: Player, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Jobs.values().filter { player.hasJob(it) }.map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Jobs.values().filter { player.hasJob(it) }.map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -3,9 +3,11 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.ecojobs.api.canJoinJob
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.joinJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.hasJob
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
@@ -28,13 +30,13 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
return
}
if (player.activeJob == job) {
if (player.hasJobActive(job)) {
player.sendMessage(plugin.langYml.getMessage("job-already-joined"))
return
}
if (player.activeJob != null) {
player.sendMessage(plugin.langYml.getMessage("leave-current-job"))
if (!player.canJoinJob(job)) {
player.sendMessage(plugin.langYml.getMessage("cannot-join-job"))
return
}
@@ -42,7 +44,8 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
plugin.langYml.getMessage("joined-job", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%job%", job.name)
)
player.activeJob = job
player.joinJob(job)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
@@ -51,8 +54,8 @@ class CommandJoin(plugin: EcoPlugin) : Subcommand(plugin, "join", "ecojobs.comma
}
val completions = mutableListOf<String>()
if (args.isEmpty()) {
// Currently, this case is not ever reached
return Jobs.values().filter { sender.hasJob(it) }.map { it.id }
}

View File

@@ -2,24 +2,46 @@ package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.leaveJob
import com.willfp.ecojobs.jobs.Jobs
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandLeave(plugin: EcoPlugin) : Subcommand(plugin, "leave", "ecojobs.command.leave", true) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
if (player.activeJob == null) {
if (args.isEmpty()) {
player.sendMessage(plugin.langYml.getMessage("needs-job"))
return
}
if (player.activeJobs.isEmpty()) {
player.sendMessage(plugin.langYml.getMessage("no-job"))
return
}
val job = player.activeJob ?: return
val id = args[0]
player.activeJob = null
val job = Jobs.getByID(id)
if (player.activeJob == null) {
if (job == null || !player.hasJob(job)) {
player.sendMessage(plugin.langYml.getMessage("invalid-job"))
return
}
if (!player.hasJobActive(job)) {
player.sendMessage(plugin.langYml.getMessage("not-in-job"))
return
}
player.leaveJob(job)
if (!player.hasJobActive(job)) {
player.sendMessage(
plugin.langYml.getMessage("left-job")
.replace("%job%", job.name)
@@ -31,4 +53,27 @@ class CommandLeave(plugin: EcoPlugin) : Subcommand(plugin, "leave", "ecojobs.com
)
}
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
if (sender !is Player) {
return emptyList()
}
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Jobs.values().filter { sender.hasJobActive(it) }.map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Jobs.values().filter { sender.hasJobActive(it) }.map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -4,10 +4,10 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecojobs.api.forceLeaveJob
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.resetJob
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.activeJob
import com.willfp.ecojobs.jobs.hasJob
import com.willfp.ecojobs.jobs.resetJob
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
@@ -44,9 +44,7 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
return
}
if (player.activeJob == job) {
player.activeJob = null
}
player.forceLeaveJob(job)
player.resetJob(job)
sender.sendMessage(

View File

@@ -4,9 +4,9 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecojobs.api.hasJob
import com.willfp.ecojobs.api.setJobLevel
import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.hasJob
import com.willfp.ecojobs.jobs.setJobLevel
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.util.StringUtil

View File

@@ -16,10 +16,18 @@ import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.formatEco
import com.willfp.eco.util.toNiceString
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.canJoinJob
import com.willfp.ecojobs.api.event.PlayerJobExpGainEvent
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
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
import com.willfp.libreforge.effects.ConfiguredEffect
@@ -30,14 +38,14 @@ import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import java.util.DoubleSummaryStatistics
import java.util.Objects
import java.util.concurrent.TimeUnit
import kotlin.math.abs
import kotlin.math.max
class Job(
val id: String,
val config: Config,
private val plugin: EcoJobsPlugin
val id: String, val config: Config, private val plugin: EcoJobsPlugin
) {
val name = config.getFormattedString("name")
val description = config.getFormattedString("description")
@@ -45,13 +53,11 @@ class Job(
val resetsOnQuit = config.getBool("reset-on-quit")
val joinPrice = ConfiguredPrice.create(config.getSubsection("join-price")) ?: ConfiguredPrice(
PriceEconomy(config.getDouble("join-price")),
""
PriceEconomy(config.getDouble("join-price")), ""
)
val leavePrice = ConfiguredPrice.create(config.getSubsection("leave-price")) ?: ConfiguredPrice(
PriceEconomy(config.getDouble("leave-price")),
""
PriceEconomy(config.getDouble("leave-price")), ""
)
val levelKey: PersistentDataKey<Int> = PersistentDataKey(
@@ -61,9 +67,7 @@ class Job(
)
val xpKey: PersistentDataKey<Double> = PersistentDataKey(
EcoJobsPlugin.instance.namespacedKeyFactory.create("${id}_xp"),
PersistentDataKeyType.DOUBLE,
0.0
EcoJobsPlugin.instance.namespacedKeyFactory.create("${id}_xp"), PersistentDataKeyType.DOUBLE, 0.0
)
private val levelXpRequirements = listOf(0) + config.getInts("level-xp-requirements")
@@ -79,25 +83,19 @@ class Job(
private val effects: Set<ConfiguredEffect>
private val conditions: Set<ConfiguredCondition>
private val levels = Caffeine.newBuilder()
.build<Int, JobLevel>()
private val effectsDescription = Caffeine.newBuilder()
.build<Int, List<String>>()
private val rewardsDescription = Caffeine.newBuilder()
.build<Int, List<String>>()
private val levelUpMessages = Caffeine.newBuilder()
.build<Int, List<String>>()
private val levels = Caffeine.newBuilder().build<Int, JobLevel>()
private val effectsDescription = Caffeine.newBuilder().build<Int, List<String>>()
private val rewardsDescription = Caffeine.newBuilder().build<Int, List<String>>()
private val levelUpMessages = Caffeine.newBuilder().build<Int, List<String>>()
private val levelCommands = mutableMapOf<Int, MutableList<String>>()
private val levelPlaceholders = config.getSubsections("level-placeholders")
.map { sub ->
private val levelPlaceholders = config.getSubsections("level-placeholders").map { sub ->
LevelPlaceholder(
sub.getString("id")
) {
NumberUtils.evaluateExpression(
sub.getString("value")
.replace("%level%", it.toString())
sub.getString("value").replace("%level%", it.toString())
).toNiceString()
}
}
@@ -107,13 +105,11 @@ class Job(
}
init {
config.injectPlaceholders(
PlayerStaticPlaceholder(
config.injectPlaceholders(PlayerStaticPlaceholder(
"level"
) { p ->
p.getJobLevel(this).toString()
}
)
})
effects = config.getSubsections("effects").mapNotNull {
Effects.compile(it, "Job $id")
@@ -143,52 +139,51 @@ class Job(
}
PlayerPlaceholder(
plugin,
"${id}_percentage_progress"
plugin, "${id}_percentage_progress"
) {
(it.getJobProgress(this) * 100).toNiceString()
}.register()
PlayerPlaceholder(
plugin,
id
plugin, id
) {
it.getJobLevel(this).toString()
}.register()
PlayerPlaceholder(
plugin,
"${id}_current_xp"
plugin, "${id}_current_xp"
) {
NumberUtils.format(it.getJobXP(this))
}.register()
PlayerPlaceholder(
plugin,
"${id}_required_xp"
plugin, "${id}_required_xp"
) {
it.getJobXPRequired(this).toString()
}.register()
PlayerlessPlaceholder(
plugin,
"${id}_name"
plugin, "${id}_name"
) {
this.name
}.register()
PlayerPlaceholder(
plugin,
"${id}_level"
plugin, "${id}_level"
) {
it.getJobLevel(this).toString()
}.register()
PlayerPlaceholder(
plugin,
"${id}_total_players"
plugin, "${id}_active"
) {
Bukkit.getOfflinePlayers().count { it.activeJob == this }.toString()
it.hasJobActive(this).toString()
}.register()
PlayerPlaceholder(
plugin, "${id}_total_players"
) {
Bukkit.getOfflinePlayers().count { this in it.activeJobs }.toString()
}.register()
}
@@ -208,11 +203,9 @@ class Job(
}
}
this.config.getStrings("level-up-messages.$highestConfiguredLevel")
.map {
this.config.getStrings("level-up-messages.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}
.map {
}.map {
" ".repeat(whitespace) + it
}
}
@@ -229,11 +222,9 @@ class Job(
}
}
this.config.getStrings("effects-description.$highestConfiguredLevel")
.map {
this.config.getStrings("effects-description.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}
.map {
}.map {
" ".repeat(whitespace) + it
}
}
@@ -250,36 +241,27 @@ class Job(
}
}
this.config.getStrings("rewards-description.$highestConfiguredLevel")
.map {
this.config.getStrings("rewards-description.$highestConfiguredLevel").map {
levelPlaceholders.format(it, level)
}
.map {
}.map {
" ".repeat(whitespace) + it
}
}
private fun getLeaveLore(level: Int, whitespace: Int = 0): List<String> =
this.config.getStrings("leave-lore")
.map {
private fun getLeaveLore(level: Int, whitespace: Int = 0): List<String> = this.config.getStrings("leave-lore").map {
levelPlaceholders.format(it, level)
}
.map {
}.map {
" ".repeat(whitespace) + it
}
private fun getJoinLore(level: Int, whitespace: Int = 0): List<String> =
this.config.getStrings("join-lore")
.map {
private fun getJoinLore(level: Int, whitespace: Int = 0): List<String> = this.config.getStrings("join-lore").map {
levelPlaceholders.format(it, level)
}
.map {
}.map {
" ".repeat(whitespace) + it
}
fun injectPlaceholdersInto(lore: List<String>, player: Player, forceLevel: Int? = null): List<String> {
val withPlaceholders = lore
.map {
val withPlaceholders = lore.map {
it.replace("%percentage_progress%", (player.getJobProgress(this) * 100).toNiceString())
.replace("%current_xp%", player.getJobXP(this).toNiceString())
.replace("%required_xp%", this.getExpForLevel(player.getJobLevel(this) + 1).let { req ->
@@ -288,15 +270,11 @@ class Job(
} else {
req.toNiceString()
}
}
)
.replace("%description%", this.description)
.replace("%job%", this.name)
}).replace("%description%", this.description).replace("%job%", this.name)
.replace("%level%", (forceLevel ?: player.getJobLevel(this)).toString())
.replace("%join_price%", this.joinPrice.getDisplay(player))
.replace("%leave_price%", this.leavePrice.getDisplay(player))
}
.toMutableList()
}.toMutableList()
val processed = mutableListOf<List<String>>()
@@ -328,35 +306,32 @@ class Job(
val level = player.getJobLevel(this)
return ItemStackBuilder(base)
.setDisplayName(
plugin.configYml.getFormattedString("gui.job-icon.name")
.replace("%level%", level.toString())
return ItemStackBuilder(base).setDisplayName(
plugin.configYml.getFormattedString("gui.job-icon.name").replace("%level%", level.toString())
.replace("%job%", this.name)
)
.addLoreLines {
injectPlaceholdersInto(plugin.configYml.getStrings("gui.job-icon.lore"), player) +
when (player.activeJob) {
this -> plugin.configYml.getStrings("gui.job-icon.active-lore")
null -> plugin.configYml.getStrings("gui.job-icon.join-lore")
else -> emptyList()
).addLoreLines {
injectPlaceholdersInto(
plugin.configYml.getStrings("gui.job-icon.lore"), player
) + 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")
} else {
emptyList()
}
}
.build()
}.build()
}
fun getJobInfoIcon(player: Player): ItemStack {
val base = baseItem.clone()
return ItemStackBuilder(base)
.setDisplayName(
return ItemStackBuilder(base).setDisplayName(
plugin.configYml.getFormattedString("gui.job-info.active.name")
.replace("%level%", player.getJobLevel(this).toString())
.replace("%job%", this.name)
)
.addLoreLines {
.replace("%level%", player.getJobLevel(this).toString()).replace("%job%", this.name)
).addLoreLines {
injectPlaceholdersInto(plugin.configYml.getStrings("gui.job-info.active.lore"), player)
}
.build()
}.build()
}
fun getExpForLevel(level: Int): Int {
@@ -393,8 +368,7 @@ class Job(
}
private class LevelPlaceholder(
val id: String,
private val function: (Int) -> String
val id: String, private val function: (Int) -> String
) {
operator fun invoke(level: Int) = function(level)
}
@@ -407,85 +381,11 @@ private fun Collection<LevelPlaceholder>.format(string: String, level: Int): Str
return process
}
private val activeJobKey: PersistentDataKey<String> = PersistentDataKey(
EcoJobsPlugin.instance.namespacedKeyFactory.create("active_job"),
PersistentDataKeyType.STRING,
""
)
fun OfflinePlayer.getJobLevelObject(job: Job): JobLevel = job.getLevel(this.getJobLevel(job))
var OfflinePlayer.activeJob: Job?
get() = Jobs.getByID(this.profile.read(activeJobKey))
set(job) {
val oldJob = this.activeJob
if (oldJob != job) {
// Have to check for oldJob too to have null safety
if (job == null && oldJob != null) {
val event = PlayerJobLeaveEvent(this, oldJob)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
}
// Not using else because null safety as well
if (job != null) {
val event = PlayerJobJoinEvent(this, job, oldJob)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
}
}
this.profile.write(activeJobKey, job?.id ?: "")
}
val OfflinePlayer.activeJobLevel: JobLevel?
get() {
val active = this.activeJob ?: return null
return this.getJobLevelObject(active)
}
fun OfflinePlayer.getJobLevel(job: Job): Int =
this.profile.read(job.levelKey)
fun OfflinePlayer.setJobLevel(job: Job, level: Int) =
this.profile.write(job.levelKey, level)
fun OfflinePlayer.resetJob(job: Job) {
this.setJobLevel(job, 1)
this.setJobXP(job, 0.0)
}
fun OfflinePlayer.getJobProgress(job: Job): Double {
val currentXP = this.getJobXP(job)
val requiredXP = job.getExpForLevel(this.getJobLevel(job) + 1)
return currentXP / requiredXP
}
fun OfflinePlayer.getJobLevelObject(job: Job): JobLevel =
job.getLevel(this.getJobLevel(job))
fun OfflinePlayer.hasJob(job: Job): Boolean =
this.getJobLevel(job) > 0
fun OfflinePlayer.getJobXP(job: Job): Double =
this.profile.read(job.xpKey)
fun OfflinePlayer.setJobXP(job: Job, xp: Double) =
this.profile.write(job.xpKey, xp)
fun OfflinePlayer.getJobXPRequired(job: Job): Int =
job.getExpForLevel(this.getJobLevel(job) + 1)
private val expMultiplierCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.build<Player, Double> {
private val expMultiplierCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build<Player, Double> {
it.cacheJobExperienceMultiplier()
}
}
val Player.jobExperienceMultiplier: Double
get() = expMultiplierCache.get(this)
@@ -507,43 +407,19 @@ private fun Player.cacheJobExperienceMultiplier(): Double {
return 1.5
}
val prefix = "ecojobs.xpmultiplier."
return 1 + getNumericalPermission("ecojobs.xpmultiplier", 0.0) / 100
}
fun Player.getNumericalPermission(permission: String, default: Double): Double {
var highest: Double? = null
for (permissionAttachmentInfo in this.effectivePermissions) {
val permission = permissionAttachmentInfo.permission
if (permission.startsWith(prefix)) {
return ((permission.substring(permission.lastIndexOf(".") + 1).toDoubleOrNull() ?: 100.0) / 100) + 1
val perm = permissionAttachmentInfo.permission
if (perm.startsWith(permission)) {
val found = perm.substring(perm.lastIndexOf(".") + 1).toDoubleOrNull() ?: continue
highest = max(highest ?: Double.MIN_VALUE, found)
}
}
return 1.0
}
fun Player.giveJobExperience(job: Job, experience: Double, noMultiply: Boolean = false) {
val exp = abs(if (noMultiply) experience else experience * this.jobExperienceMultiplier)
val gainEvent = PlayerJobExpGainEvent(this, job, exp, !noMultiply)
Bukkit.getPluginManager().callEvent(gainEvent)
if (gainEvent.isCancelled) {
return
}
this.giveExactJobExperience(job, gainEvent.amount)
}
fun Player.giveExactJobExperience(job: Job, experience: Double) {
val level = this.getJobLevel(job)
val progress = this.getJobXP(job) + experience
if (progress >= job.getExpForLevel(level + 1) && level + 1 <= job.maxLevel) {
val overshoot = progress - job.getExpForLevel(level + 1)
this.setJobXP(job, 0.0)
this.setJobLevel(job, level + 1)
val levelUpEvent = PlayerJobLevelUpEvent(this, job, level + 1)
Bukkit.getPluginManager().callEvent(levelUpEvent)
this.giveExactJobExperience(job, overshoot)
} else {
this.setJobXP(job, progress)
}
return highest ?: default
}

View File

@@ -9,6 +9,8 @@ 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.util.formatEco
import com.willfp.ecojobs.api.hasJobActive
import com.willfp.ecojobs.api.leaveJob
import org.bukkit.entity.Player
class JobLeaveGUI(
@@ -59,9 +61,9 @@ class JobLeaveGUI(
.build()
}) {
onLeftClick { player, _, _, _ ->
player.activeJob = null
player.leaveJob(job)
if (player.activeJob == null) {
if (!player.hasJobActive(job)) {
player.sendMessage(
plugin.langYml.getMessage("left-job")
.replace("%job%", job.name)

View File

@@ -13,6 +13,7 @@ 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.util.NumberUtils
import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecomponent.components.LevelComponent
import com.willfp.ecomponent.components.LevelState
import org.bukkit.entity.Player

View File

@@ -1,5 +1,7 @@
package com.willfp.ecojobs.jobs
import com.willfp.ecojobs.api.activeJobs
import com.willfp.ecojobs.api.giveJobExperience
import com.willfp.libreforge.events.TriggerPreProcessEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
@@ -9,8 +11,9 @@ object JobTriggerXPGainListener : Listener {
fun handle(event: TriggerPreProcessEvent) {
val player = event.player
val job = event.player.activeJob ?: return
val jobs = event.player.activeJobs
for (job in jobs) {
val amount = job.getXP(event)
if (amount <= 0.0) {
@@ -19,4 +22,5 @@ object JobTriggerXPGainListener : Listener {
player.giveJobExperience(job, amount)
}
}
}

View File

@@ -5,6 +5,7 @@ import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.ecojobs.EcoJobsPlugin
import com.willfp.ecojobs.api.getJobLevel
import org.bukkit.OfflinePlayer
object Jobs {

View File

@@ -4,18 +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
@@ -23,17 +33,6 @@ import kotlin.math.min
object JobsGUI {
private lateinit var menu: Menu
private val jobAreaSlots = mutableListOf<Pair<Int, Int>>()
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
@@ -54,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
@@ -86,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
}
)
@@ -100,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
@@ -111,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(
@@ -124,51 +156,57 @@ 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
.build(),
PageChanger.Direction.FORWARDS
)
)
val pages = ceil(Jobs.values()
maxPages { player ->
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)
}
}
)
setSlot(plugin.configYml.getInt("gui.close.location.row"),
plugin.configYml.getInt("gui.close.location.column"),
@@ -181,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"),

View File

@@ -1,6 +1,7 @@
package com.willfp.ecojobs.jobs
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
import com.willfp.ecojobs.api.resetJob
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener

View File

@@ -3,6 +3,10 @@
# by Auxilor
#
jobs:
limit: 3 # The most jobs a player can have at once.
# You can set custom limits with the ecojobs.limit.<number> permission
gui:
rows: 6
@@ -20,49 +24,43 @@ 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:
row: 2
column: 2
player-info:
row: 1
column: 5
no-active:
name: "&cNo Active Job"
lore:
name: "&r%player%&f's Jobs:"
no-jobs:
- ""
- "&cYou do not currently have a job active"
- "&fPick one from the options below!"
- ""
item: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19
# %join_price% and %leave_price% are also available as placeholders
active:
name: "%job% &fLvl. &a%level%"
lore:
- "%description%"
- "&f"
- "&fJob Rewards:"
- "%effects%"
- "&fYou can have up to &a%ecojobs_limit% &fjobs at once!"
- ""
- "&fProgress:"
- "&8» &e%percentage_progress%%"
- "&8» &e%current_xp%&8/&7%required_xp% &fXP"
has-jobs:
- ""
- "&eClick to view Level Progression!"
- "%jobs%"
- ""
- "&fJob slots in use: &a%ecojobs_in_jobs%&8/&a%ecojobs_limit%"
job-line:
- " %job% &fLvl. &a%level%"
job-icon:
name: "%job% &fLvl. &a%level%"
@@ -76,9 +74,16 @@ 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:
- ""
- "&cYou have too many jobs already!"
join-lore:
- ""
@@ -93,28 +98,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: [ ]

View File

@@ -1,5 +1,5 @@
name: "&#FB8810Lumberjack"
description: "&8&oLevel up by chopping wood"
name: "&#FD9113Lumberjack"
description: "&7&oLevel up by chopping wood"
unlocked-by-default: true
@@ -74,56 +74,57 @@ level-xp-requirements:
xp-gain-methods:
- trigger: mine_block
multiplier: 0.5
conditions: [ ]
filters:
items:
- "*oak_log"
- "*spruce_log"
- "*birch_log"
- "*jungle_log"
- "*acacia_log"
- "*dark_oak_log"
- "*mangrove_log"
- "*crimson_stem"
- "*warped_stem"
blocks:
- oak_log
- spruce_log
- birch_log
- jungle_log
- acacia_log
- dark_oak_log
- mangrove_log
- crimson_stem
- warped_stem
player_placed: false
conditions: [ ]
level-placeholders:
- id: "money"
value: "%level% * 0.4"
value: "%level% * 3.0"
effects-description:
1:
- "&8» &8Earn &a$%money%&8 for each log chopped."
- "&8» &7Earn &a$%money%&7 for each log chopped."
rewards-description:
1:
- "&8» &8Earn &a$%money%&8 for each log chopped."
- "&8» &7Earn &a$%money%&7 for each log chopped."
level-up-messages:
1:
- "&8» &8Earn &a$%money%&8 for each log chopped."
- "&8» &7Earn &a$%money%&7 for each log chopped."
level-commands: [ ]
effects:
- id: give_money
args:
every: "ceil(10 - %level% / 10)"
amount: "0.4 * %level%"
filters:
items:
- "*oak_log"
- "*spruce_log"
- "*birch_log"
- "*jungle_log"
- "*acacia_log"
- "*dark_oak_log"
- "*mangrove_log"
- "*crimson_stem"
- "*warped_stem"
amount: "%level% * 3.0"
triggers:
- mine_block
filters:
blocks:
- oak_log
- spruce_log
- birch_log
- jungle_log
- acacia_log
- dark_oak_log
- mangrove_log
- crimson_stem
- warped_stem
player_placed: false
conditions: [ ]
icon: player_head texture:basehead-eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2E2MjA3MDJmODBiZDJjMjI0MmUyZjEzMWMzZjlhMjU5NDAyYjdmYTg5NzRjODZjZjM0NTBmZjczZTc3MDU5NSJ9fX0=
icon: player_head texture:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjk4NWEwNWQyYTMzOWExYzFiZDdlMmE3OWFlMDAyNWI5YTEwZTg0ZGI5OWFkZjQzNThkNmViZTgzNThhZDJkOCJ9fX0=

View File

@@ -33,8 +33,10 @@ 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!"
menu:
title: "Jobs"

View File

@@ -1,4 +1,4 @@
#libreforge-updater
#Sat Nov 12 17:33:55 GMT 2022
version=1.25.0
#Wed Feb 15 20:57:47 GMT 2023
version=2.0.0
plugin-name=EcoJobs