9
0
mirror of https://github.com/Auxilor/EcoJobs.git synced 2025-12-19 15:09:24 +00:00

Improved EcoJobs top placeholder and added new /jobs top command

This commit is contained in:
Exanthiax
2025-08-27 18:57:43 +01:00
parent ec8ddba84c
commit 662e978cbf
8 changed files with 161 additions and 31 deletions

View File

@@ -10,6 +10,7 @@ import com.willfp.ecojobs.api.getJobLevel
import com.willfp.ecojobs.api.jobLimit import com.willfp.ecojobs.api.jobLimit
import com.willfp.ecojobs.commands.CommandEcoJobs import com.willfp.ecojobs.commands.CommandEcoJobs
import com.willfp.ecojobs.commands.CommandJobs import com.willfp.ecojobs.commands.CommandJobs
import com.willfp.ecojobs.jobs.EcoJobsJobTopPlaceholder
import com.willfp.ecojobs.jobs.JobLevelListener import com.willfp.ecojobs.jobs.JobLevelListener
import com.willfp.ecojobs.jobs.Jobs import com.willfp.ecojobs.jobs.Jobs
import com.willfp.ecojobs.jobs.PriceHandler import com.willfp.ecojobs.jobs.PriceHandler
@@ -64,6 +65,8 @@ class EcoJobsPlugin : LibreforgePlugin() {
} }
} }
EcoJobsJobTopPlaceholder(this).register()
PlayerPlaceholder( PlayerPlaceholder(
this, this,
"limit" "limit"
@@ -84,28 +87,6 @@ class EcoJobsPlugin : LibreforgePlugin() {
} }
level.toString() level.toString()
}.register() }.register()
DynamicPlaceholder(
this,
Pattern.compile("top_[a-z]+_[0-9]+_[a-z]+")
) {
val split = it.split("_")
val jobId = split.getOrNull(1) ?: return@DynamicPlaceholder "You must specify the job id!"
val job = Jobs.getByID(jobId) ?: return@DynamicPlaceholder "Invalid job id!"
val placeString = split.getOrNull(2) ?: return@DynamicPlaceholder "You must specify the place!"
val place = placeString.toIntOrNull() ?: return@DynamicPlaceholder "Invalid place!"
val type = split.getOrNull(3) ?: return@DynamicPlaceholder "You must specify the top type!"
val topEntry = job.getTop(place)
return@DynamicPlaceholder when (type) {
"name" -> topEntry?.player?.savedDisplayName
?: this.langYml.getFormattedString("top.name-empty")
"amount" -> topEntry?.amount?.toNiceString()
?: this.langYml.getFormattedString("top.amount-empty")
else -> "Invalid type: $type! Available types: name/amount"
}
}.register()
} }
override fun loadPluginCommands(): List<PluginCommand> { override fun loadPluginCommands(): List<PluginCommand> {

View File

@@ -12,6 +12,7 @@ class CommandJobs(plugin: EcoPlugin) : PluginCommand(plugin, "jobs", "ecojobs.co
init { init {
this.addSubcommand(CommandJoin(plugin)) this.addSubcommand(CommandJoin(plugin))
.addSubcommand(CommandLeave(plugin)) .addSubcommand(CommandLeave(plugin))
.addSubcommand(CommandTop(plugin))
} }
override fun onExecute(player: Player, args: List<String>) { override fun onExecute(player: Player, args: List<String>) {

View File

@@ -0,0 +1,87 @@
package com.willfp.ecojobs.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.core.placeholder.context.placeholderContext
import com.willfp.eco.util.formatEco
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecojobs.jobs.Jobs
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandTop(plugin: EcoPlugin) : Subcommand(plugin, "top", "ecojobs.command.top", false) {
override fun onExecute(sender: CommandSender, args: List<String>) {
plugin.scheduler.runAsync {
val job = Jobs.getByID(args.getOrNull(0))
if (job == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-job"))
return@runAsync
}
val page = args.getOrNull(1)?.toIntOrNull() ?: 1
if (args.getOrNull(1)?.let { it.isNotBlank() && !it.matches("\\d+".toRegex()) } == true) {
sender.sendMessage(plugin.langYml.getMessage("invalid-page"))
return@runAsync
}
val offset = (page - 1) * 10
val positions = (offset + 1..offset + 10).toList()
val top = positions.mapNotNull { job.getTop(it) }
val messages = plugin.langYml.getStrings("top.format").toMutableList()
val lines = mutableListOf<String>()
top.forEachIndexed { index, entry ->
val line = plugin.langYml.getString("top-line-format")
.replace("%rank%", (offset + index + 1).toString())
.replace("%level%", entry.level.toString())
.replace("%player%", entry.player.savedDisplayName)
lines.add(line)
}
val linesIndex = messages.indexOf("%lines%")
if (linesIndex != -1) {
messages.removeAt(linesIndex)
messages.addAll(linesIndex, lines)
}
messages.forEach { message ->
sender.sendMessage(
message.formatEco(
placeholderContext(
player = sender as? Player
)
)
)
}
}
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Jobs.values().map { it.id },
completions
)
return completions
}
if (args.size == 2 && Jobs.getByID(args[0]) != null) {
StringUtil.copyPartialMatches(
args[1],
listOf("1", "2", "3", "4", "5"),
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -0,0 +1,37 @@
package com.willfp.ecojobs.jobs
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.placeholder.RegistrablePlaceholder
import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.util.savedDisplayName
import java.util.regex.Pattern
class EcoJobsJobTopPlaceholder(
private val plugin: EcoPlugin
) : RegistrablePlaceholder {
private val pattern = Pattern.compile("top_([a-z0-9_]+)_(\\d+)_(name|level|amount)")
override fun getPattern(): Pattern = pattern
override fun getPlugin(): EcoPlugin = plugin
override fun getValue(params: String, ctx: PlaceholderContext): String? {
val emptyPosition: String = plugin.langYml.getString("top.empty-position")
val matcher = pattern.matcher(params)
if (!matcher.matches()) {
return null
}
val jobId = matcher.group(1)
val place = matcher.group(2).toIntOrNull() ?: return null
val type = matcher.group(3)
val job = Jobs.getByID(jobId) ?: return null
return when (type) {
"name" -> job.getTop(place)?.player?.savedDisplayName ?: emptyPosition
"level", "amount" -> job.getTop(place)?.level?.toString() ?: emptyPosition
else -> null
}
}
}

View File

@@ -42,6 +42,7 @@ import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.time.Duration import java.time.Duration
import java.util.Objects import java.util.Objects
import java.util.UUID
class Job( class Job(
val id: String, val id: String,
@@ -184,6 +185,14 @@ class Job(
) { ) {
Bukkit.getOfflinePlayers().count { this in it.activeJobs }.toString() Bukkit.getOfflinePlayers().count { this in it.activeJobs }.toString()
}.register() }.register()
PlayerPlaceholder(
plugin, "${id}_leaderboard_rank"
) { player ->
val emptyPosition = plugin.langYml.getString("top.empty-position")
val position = getPosition(player.uniqueId)
position?.toString() ?: emptyPosition
}.register()
} }
@Deprecated("Use level-up-effects instead") @Deprecated("Use level-up-effects instead")
@@ -321,6 +330,7 @@ class Job(
.replace("%level_numeral%", NumberUtils.toNumeral(forceLevel ?: player.getJobLevel(this))) .replace("%level_numeral%", NumberUtils.toNumeral(forceLevel ?: player.getJobLevel(this)))
.replace("%join_price%", this.joinPrice.getDisplay(player)) .replace("%join_price%", this.joinPrice.getDisplay(player))
.replace("%leave_price%", this.leavePrice.getDisplay(player)) .replace("%leave_price%", this.leavePrice.getDisplay(player))
.replace("%rank%", this.getPosition(player.uniqueId)?.toString() ?: plugin.langYml.getString("top.empty-position"))
val level = forceLevel ?: player.getJobLevel(this) val level = forceLevel ?: player.getJobLevel(this)
val regex = Regex("%level_(-?\\d+)(_numeral)?%") val regex = Regex("%level_(-?\\d+)(_numeral)?%")
@@ -442,6 +452,14 @@ class Job(
} }
} }
fun getPosition(uuid: UUID): Int? {
val leaderboard = Bukkit.getOfflinePlayers().sortedByDescending { it.getJobLevel(this) }
.map { it.uniqueId }
val index = leaderboard.indexOf(uuid)
return if (index == -1) null else index + 1
}
override fun getID(): String { override fun getID(): String {
return this.id return this.id
} }
@@ -465,11 +483,6 @@ private class LevelPlaceholder(
operator fun invoke(level: Int) = function(level) operator fun invoke(level: Int) = function(level)
} }
data class LeaderboardCacheEntry(
val player: OfflinePlayer,
val amount: Int
)
private fun Collection<LevelPlaceholder>.format(string: String, level: Int): String { private fun Collection<LevelPlaceholder>.format(string: String, level: Int): String {
var process = string var process = string
for (placeholder in this) { for (placeholder in this) {

View File

@@ -30,8 +30,8 @@ object Jobs : ConfigCategory("job", "jobs") {
* @return The matching [Job], or null if not found. * @return The matching [Job], or null if not found.
*/ */
@JvmStatic @JvmStatic
fun getByID(name: String): Job? { fun getByID(name: String?): Job? {
return registry[name] return name?.let { registry[it] }
} }
override fun clear(plugin: LibreforgePlugin) { override fun clear(plugin: LibreforgePlugin) {

View File

@@ -0,0 +1,8 @@
package com.willfp.ecojobs.util
import org.bukkit.OfflinePlayer
data class LeaderboardCacheEntry(
val player: OfflinePlayer,
val level: Int
)

View File

@@ -34,6 +34,9 @@ menu:
infinity: "∞" infinity: "∞"
top-line-format: "%rank%. %player% - %level%"
top: top:
name-empty: "&cEmpty" empty-position: "&cN/A"
amount-empty: "0" format:
- "---- Jobs Leaderboard ----"
- "%lines%"