mirror of
https://github.com/Auxilor/EcoJobs.git
synced 2025-12-20 15:39:26 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
662e978cbf | ||
|
|
ec8ddba84c | ||
|
|
1a6c879305 | ||
|
|
682446aa90 | ||
|
|
2e2f44a387 | ||
|
|
ec1fe90c8c | ||
|
|
7420415514 | ||
|
|
11bce9975d | ||
|
|
013d8a0068 | ||
|
|
338c1c3499 | ||
|
|
cdcc45aef8 | ||
|
|
533d036a18 | ||
|
|
03e99e2e1e | ||
|
|
86b7ad2971 | ||
|
|
7065642d97 | ||
|
|
e6c486bc3a | ||
|
|
c99769a1e3 | ||
|
|
6fc1ba72d8 | ||
|
|
b08687eba2 | ||
|
|
8cd544b327 | ||
|
|
5d40c32c1e | ||
|
|
ee155ccca6 | ||
|
|
acdb4d0f78 | ||
|
|
b99a72808c | ||
|
|
6bd56c8d95 | ||
|
|
e90f321517 | ||
|
|
4c021781e5 | ||
|
|
abfce4428f |
@@ -1,9 +1,11 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
kotlin("jvm") version "1.9.20"
|
||||
id("io.github.goooler.shadow") version "8.1.7"
|
||||
kotlin("jvm") version "2.1.0"
|
||||
id("com.gradleup.shadow") version "8.3.0"
|
||||
id("com.willfp.libreforge-gradle-plugin") version "1.0.0"
|
||||
}
|
||||
|
||||
@@ -25,7 +27,7 @@ allprojects {
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "kotlin")
|
||||
apply(plugin = "maven-publish")
|
||||
apply(plugin = "io.github.goooler.shadow")
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@@ -37,9 +39,9 @@ allprojects {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.willfp:eco:6.55.0")
|
||||
compileOnly("com.willfp:eco:6.56.0")
|
||||
compileOnly("org.jetbrains:annotations:23.0.0")
|
||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
|
||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -54,8 +56,8 @@ allprojects {
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ 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.EcoJobsJobTopPlaceholder
|
||||
import com.willfp.ecojobs.jobs.JobLevelListener
|
||||
import com.willfp.ecojobs.jobs.Jobs
|
||||
import com.willfp.ecojobs.jobs.PriceHandler
|
||||
@@ -64,6 +65,8 @@ class EcoJobsPlugin : LibreforgePlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
EcoJobsJobTopPlaceholder(this).register()
|
||||
|
||||
PlayerPlaceholder(
|
||||
this,
|
||||
"limit"
|
||||
@@ -84,28 +87,6 @@ class EcoJobsPlugin : LibreforgePlugin() {
|
||||
}
|
||||
level.toString()
|
||||
}.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> {
|
||||
|
||||
@@ -140,7 +140,7 @@ fun OfflinePlayer.resetJob(job: Job) {
|
||||
/**
|
||||
* Get the experience required to advance to the next level.
|
||||
*/
|
||||
fun OfflinePlayer.getJobXPRequired(job: Job) = job.getExpForLevel(this.getJobLevel(job) + 1)
|
||||
fun OfflinePlayer.getJobXPRequired(job: Job) = job.getFormattedExpForLevel(this.getJobLevel(job) + 1)
|
||||
|
||||
/**
|
||||
* Get progress to next level between 0 and 1, where 0 is none and 1 is complete.
|
||||
|
||||
@@ -12,6 +12,7 @@ class CommandJobs(plugin: EcoPlugin) : PluginCommand(plugin, "jobs", "ecojobs.co
|
||||
init {
|
||||
this.addSubcommand(CommandJoin(plugin))
|
||||
.addSubcommand(CommandLeave(plugin))
|
||||
.addSubcommand(CommandTop(plugin))
|
||||
}
|
||||
|
||||
override fun onExecute(player: Player, args: List<String>) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.willfp.ecojobs.api.resetJob
|
||||
import com.willfp.ecojobs.jobs.Jobs
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.util.StringUtil
|
||||
|
||||
class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.command.reset", false) {
|
||||
override fun onExecute(sender: CommandSender, args: List<String>) {
|
||||
@@ -24,16 +25,68 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
|
||||
}
|
||||
|
||||
val playerName = args[0]
|
||||
val jobName = args[1]
|
||||
|
||||
// Reset all jobs for all players
|
||||
if (playerName.equals("all", ignoreCase = true) && jobName.equals("all", ignoreCase = true)) {
|
||||
Bukkit.getOnlinePlayers().forEach { player ->
|
||||
Jobs.values().forEach { job ->
|
||||
if (player.hasJob(job)) {
|
||||
player.forceLeaveJob(job)
|
||||
player.resetJob(job)
|
||||
}
|
||||
}
|
||||
}
|
||||
sender.sendMessage(plugin.langYml.getMessage("reset-all-players-all-jobs"))
|
||||
return
|
||||
}
|
||||
|
||||
// Reset a specific job for all players
|
||||
if (playerName.equals("all", ignoreCase = true)) {
|
||||
val job = Jobs.getByID(jobName)
|
||||
if (job == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-job"))
|
||||
return
|
||||
}
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { player ->
|
||||
if (player.hasJob(job)) {
|
||||
player.forceLeaveJob(job)
|
||||
player.resetJob(job)
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(
|
||||
plugin.langYml.getMessage("reset-all-players")
|
||||
.replace("%job%", job.name)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Reset all jobs for a specific player
|
||||
val player = Bukkit.getPlayer(playerName)
|
||||
|
||||
if (player == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-player"))
|
||||
return
|
||||
}
|
||||
|
||||
val job = Jobs.getByID(args[1])
|
||||
if (jobName.equals("all", ignoreCase = true)) {
|
||||
Jobs.values().forEach { job ->
|
||||
if (player.hasJob(job)) {
|
||||
player.forceLeaveJob(job)
|
||||
player.resetJob(job)
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(
|
||||
plugin.langYml.getMessage("reset-all-jobs")
|
||||
.replace("%player%", player.savedDisplayName)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Reset a specific job for a specific player
|
||||
val job = Jobs.getByID(jobName)
|
||||
if (job == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-job"))
|
||||
return
|
||||
@@ -55,12 +108,23 @@ class CommandReset(plugin: EcoPlugin) : Subcommand(plugin, "reset", "ecojobs.com
|
||||
}
|
||||
|
||||
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
|
||||
val completions = mutableListOf<String>()
|
||||
if (args.size == 1) {
|
||||
return Bukkit.getOnlinePlayers().map { it.name }
|
||||
StringUtil.copyPartialMatches(
|
||||
args[0],
|
||||
listOf("all") union Bukkit.getOnlinePlayers().map { player -> player.name },
|
||||
completions
|
||||
)
|
||||
return completions
|
||||
}
|
||||
|
||||
if (args.size == 2) {
|
||||
return Jobs.values().map { it.id }
|
||||
StringUtil.copyPartialMatches(
|
||||
args[1],
|
||||
listOf("all") union Jobs.values().map { it.id },
|
||||
completions
|
||||
)
|
||||
return completions
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,15 @@ import com.willfp.eco.core.items.builder.ItemStackBuilder
|
||||
import com.willfp.eco.core.placeholder.PlayerPlaceholder
|
||||
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder
|
||||
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
|
||||
import com.willfp.eco.core.placeholder.context.placeholderContext
|
||||
import com.willfp.eco.core.price.ConfiguredPrice
|
||||
import com.willfp.eco.core.price.impl.PriceEconomy
|
||||
import com.willfp.eco.core.registry.Registrable
|
||||
import com.willfp.eco.util.NumberUtils
|
||||
import com.willfp.eco.util.NumberUtils.evaluateExpression
|
||||
import com.willfp.eco.util.formatEco
|
||||
import com.willfp.eco.util.toNiceString
|
||||
import com.willfp.eco.util.toNumeral
|
||||
import com.willfp.ecojobs.EcoJobsPlugin
|
||||
import com.willfp.ecojobs.api.activeJobs
|
||||
import com.willfp.ecojobs.api.canJoinJob
|
||||
@@ -24,20 +27,22 @@ 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.ecojobs.util.LevelInjectable
|
||||
import com.willfp.libreforge.ViolationContext
|
||||
import com.willfp.libreforge.conditions.ConditionList
|
||||
import com.willfp.libreforge.conditions.Conditions
|
||||
import com.willfp.libreforge.counters.Counters
|
||||
import com.willfp.libreforge.effects.EffectList
|
||||
import com.willfp.libreforge.effects.Effects
|
||||
import com.willfp.libreforge.effects.executors.impl.NormalExecutorFactory
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.configuration.InvalidConfigurationException
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import java.time.Duration
|
||||
import java.util.Objects
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.max
|
||||
import java.util.UUID
|
||||
|
||||
class Job(
|
||||
val id: String,
|
||||
@@ -49,8 +54,11 @@ class Job(
|
||||
.build<Int, LeaderboardCacheEntry?>()
|
||||
|
||||
val name = config.getFormattedString("name")
|
||||
|
||||
val description = config.getFormattedString("description")
|
||||
|
||||
val isUnlockedByDefault = config.getBool("unlocked-by-default")
|
||||
|
||||
val resetsOnQuit = config.getBool("reset-on-quit")
|
||||
|
||||
val joinPrice = ConfiguredPrice.create(config.getSubsection("join-price")) ?: ConfiguredPrice(
|
||||
@@ -71,9 +79,11 @@ class Job(
|
||||
EcoJobsPlugin.instance.namespacedKeyFactory.create("${id}_xp"), PersistentDataKeyType.DOUBLE, 0.0
|
||||
)
|
||||
|
||||
private val xpFormula = config.getStringOrNull("xp-formula")
|
||||
|
||||
private val levelXpRequirements = listOf(0) + config.getInts("level-xp-requirements")
|
||||
|
||||
val maxLevel = levelXpRequirements.size
|
||||
val maxLevel = config.getIntOrNull("max-level") ?: levelXpRequirements?.size ?: Int.MAX_VALUE
|
||||
|
||||
val levelGUI = JobLevelGUI(plugin, this)
|
||||
|
||||
@@ -106,6 +116,10 @@ class Job(
|
||||
}
|
||||
|
||||
init {
|
||||
if (xpFormula == null && levelXpRequirements == null) {
|
||||
throw InvalidConfigurationException("Skill $id has no requirements or xp formula")
|
||||
}
|
||||
|
||||
config.injectPlaceholders(PlayerStaticPlaceholder(
|
||||
"level"
|
||||
) { p ->
|
||||
@@ -122,24 +136,7 @@ class Job(
|
||||
ViolationContext(plugin, "Job $id")
|
||||
)
|
||||
|
||||
for (string in config.getStrings("level-commands")) {
|
||||
val split = string.split(":")
|
||||
|
||||
if (split.size == 1) {
|
||||
for (level in 1..maxLevel) {
|
||||
val commands = levelCommands[level] ?: mutableListOf()
|
||||
commands.add(string)
|
||||
levelCommands[level] = commands
|
||||
}
|
||||
} else {
|
||||
val level = split[0].toInt()
|
||||
|
||||
val command = string.removePrefix("$level:")
|
||||
val commands = levelCommands[level] ?: mutableListOf()
|
||||
commands.add(command)
|
||||
levelCommands[level] = commands
|
||||
}
|
||||
}
|
||||
manageLevelCommands(config)
|
||||
|
||||
PlayerPlaceholder(
|
||||
plugin, "${id}_percentage_progress"
|
||||
@@ -188,8 +185,59 @@ class Job(
|
||||
) {
|
||||
Bukkit.getOfflinePlayers().count { this in it.activeJobs }.toString()
|
||||
}.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")
|
||||
private fun manageLevelCommands(config: Config) {
|
||||
if (config.getStrings("level-commands").isNotEmpty()) {
|
||||
plugin.logger.warning("$id job: The `level-commands` key is deprecated and will be removed in future versions. Switch to `level-up-effects` instead. Refer to the wiki for more info.")
|
||||
}
|
||||
for (string in config.getStrings("level-commands")) {
|
||||
val split = string.split(":")
|
||||
|
||||
if (split.size == 1) {
|
||||
for (level in 1..maxLevel) {
|
||||
val commands = levelCommands[level] ?: mutableListOf()
|
||||
commands.add(string)
|
||||
levelCommands[level] = commands
|
||||
}
|
||||
} else {
|
||||
val level = split[0].toInt()
|
||||
|
||||
val command = string.removePrefix("$level:")
|
||||
val commands = levelCommands[level] ?: mutableListOf()
|
||||
commands.add(command)
|
||||
levelCommands[level] = commands
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val levelUpEffects = Effects.compileChain(
|
||||
config.getSubsections("level-up-effects"),
|
||||
NormalExecutorFactory.create(),
|
||||
ViolationContext(plugin, "Job $id level-up-effects")
|
||||
)
|
||||
|
||||
val joinEffects = Effects.compileChain(
|
||||
config.getSubsections("join-effects"),
|
||||
NormalExecutorFactory.create(),
|
||||
ViolationContext(plugin, "Job $id join-effects")
|
||||
)
|
||||
|
||||
val leaveEffects = Effects.compileChain(
|
||||
config.getSubsections("leave-effects"),
|
||||
NormalExecutorFactory.create(),
|
||||
ViolationContext(plugin, "Job $id leave-effects")
|
||||
)
|
||||
|
||||
override fun onRegister() {
|
||||
jobXpGains.forEach { it.bind(JobXPAccumulator(this)) }
|
||||
}
|
||||
@@ -272,20 +320,31 @@ class Job(
|
||||
}
|
||||
|
||||
fun injectPlaceholdersInto(lore: List<String>, player: Player, forceLevel: Int? = null): List<String> {
|
||||
val withPlaceholders = lore.map {
|
||||
it.replace("%percentage_progress%", (player.getJobProgress(this) * 100).toNiceString())
|
||||
val withPlaceholders = lore.map { line ->
|
||||
var result = line
|
||||
.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 ->
|
||||
if (req == Int.MAX_VALUE) {
|
||||
plugin.langYml.getFormattedString("infinity")
|
||||
} else {
|
||||
req.toNiceString()
|
||||
}
|
||||
}).replace("%description%", this.description).replace("%job%", this.name)
|
||||
.replace("%required_xp%", this.getFormattedExpForLevel(player.getJobLevel(this) + 1))
|
||||
.replace("%description%", this.description).replace("%job%", this.name)
|
||||
.replace("%level%", (forceLevel ?: player.getJobLevel(this)).toString())
|
||||
.replace("%level_numeral%", NumberUtils.toNumeral(forceLevel ?: player.getJobLevel(this)))
|
||||
.replace("%join_price%", this.joinPrice.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 regex = Regex("%level_(-?\\d+)(_numeral)?%")
|
||||
|
||||
// Handle dynamic %level_X% and %level_X_numeral%
|
||||
result = regex.replace(result) { match ->
|
||||
val offset = match.groupValues[1].toIntOrNull() ?: return@replace match.value
|
||||
val isNumeral = match.groupValues[2].isNotEmpty()
|
||||
val newLevel = level + offset
|
||||
|
||||
if (isNumeral) newLevel.toNumeral() else newLevel.toString()
|
||||
}
|
||||
|
||||
result
|
||||
}.toMutableList()
|
||||
|
||||
val processed = mutableListOf<List<String>>()
|
||||
@@ -347,14 +406,36 @@ class Job(
|
||||
}.build()
|
||||
}
|
||||
|
||||
fun getExpForLevel(level: Int): Int {
|
||||
/**
|
||||
* Get the XP required to reach the next level, if currently at [level].
|
||||
*/
|
||||
fun getExpForLevel(level: Int): Double {
|
||||
if (level < 1 || level > maxLevel) {
|
||||
return Int.MAX_VALUE
|
||||
return Double.MAX_VALUE
|
||||
}
|
||||
|
||||
return levelXpRequirements[level - 1]
|
||||
if (xpFormula != null) {
|
||||
return evaluateExpression(
|
||||
xpFormula,
|
||||
placeholderContext(
|
||||
injectable = LevelInjectable(level - 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return levelXpRequirements[level - 1].toDouble()
|
||||
}
|
||||
|
||||
fun getFormattedExpForLevel(level: Int): String {
|
||||
val required = getExpForLevel(level)
|
||||
return if (required.isInfinite()) {
|
||||
plugin.langYml.getFormattedString("infinity")
|
||||
} else {
|
||||
required.toNiceString()
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Use level-up-effects instead")
|
||||
fun executeLevelCommands(player: Player, level: Int) {
|
||||
val commands = levelCommands[level] ?: emptyList()
|
||||
|
||||
@@ -371,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 {
|
||||
return this.id
|
||||
}
|
||||
@@ -394,11 +483,6 @@ private class LevelPlaceholder(
|
||||
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 {
|
||||
var process = string
|
||||
for (placeholder in this) {
|
||||
@@ -408,44 +492,3 @@ private fun Collection<LevelPlaceholder>.format(string: String, level: Int): Str
|
||||
}
|
||||
|
||||
fun OfflinePlayer.getJobLevelObject(job: Job): JobLevel = job.getLevel(this.getJobLevel(job))
|
||||
|
||||
private val expMultiplierCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build<Player, Double> {
|
||||
it.cacheJobExperienceMultiplier()
|
||||
}
|
||||
|
||||
val Player.jobExperienceMultiplier: Double
|
||||
get() = expMultiplierCache.get(this)
|
||||
|
||||
private fun Player.cacheJobExperienceMultiplier(): Double {
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.quadruple")) {
|
||||
return 4.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.triple")) {
|
||||
return 3.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.double")) {
|
||||
return 2.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.50percent")) {
|
||||
return 1.5
|
||||
}
|
||||
|
||||
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 perm = permissionAttachmentInfo.permission
|
||||
if (perm.startsWith(permission)) {
|
||||
val found = perm.substring(perm.lastIndexOf(".") + 1).toDoubleOrNull() ?: continue
|
||||
highest = max(highest ?: Double.MIN_VALUE, found)
|
||||
}
|
||||
}
|
||||
|
||||
return highest ?: default
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.willfp.ecojobs.jobs
|
||||
|
||||
import com.willfp.ecojobs.EcoJobsPlugin
|
||||
import com.willfp.ecojobs.api.event.PlayerJobLevelUpEvent
|
||||
import com.willfp.libreforge.toDispatcher
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
@@ -16,6 +17,7 @@ class JobLevelListener(
|
||||
val player = event.player
|
||||
val level = event.level
|
||||
|
||||
job.levelUpEffects?.trigger(player.toDispatcher())
|
||||
job.executeLevelCommands(player, level)
|
||||
|
||||
if (this.plugin.configYml.getBool("level-up.sound.enabled")) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.willfp.ecojobs.jobs
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.willfp.ecojobs.api.giveJobExperience
|
||||
import com.willfp.ecojobs.api.hasJobActive
|
||||
import com.willfp.libreforge.counters.Accumulator
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.max
|
||||
|
||||
class JobXPAccumulator(
|
||||
private val job: Job
|
||||
@@ -16,3 +19,44 @@ class JobXPAccumulator(
|
||||
player.giveJobExperience(job, count)
|
||||
}
|
||||
}
|
||||
|
||||
private val expMultiplierCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build<Player, Double> {
|
||||
it.cacheJobExperienceMultiplier()
|
||||
}
|
||||
|
||||
val Player.jobExperienceMultiplier: Double
|
||||
get() = expMultiplierCache.get(this)
|
||||
|
||||
private fun Player.cacheJobExperienceMultiplier(): Double {
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.quadruple")) {
|
||||
return 4.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.triple")) {
|
||||
return 3.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.double")) {
|
||||
return 2.0
|
||||
}
|
||||
|
||||
if (this.hasPermission("ecojobs.xpmultiplier.50percent")) {
|
||||
return 1.5
|
||||
}
|
||||
|
||||
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 perm = permissionAttachmentInfo.permission
|
||||
if (perm.startsWith(permission)) {
|
||||
val found = perm.substring(perm.lastIndexOf(".") + 1).toDoubleOrNull() ?: continue
|
||||
highest = max(highest ?: Double.MIN_VALUE, found)
|
||||
}
|
||||
}
|
||||
|
||||
return highest ?: default
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ object Jobs : ConfigCategory("job", "jobs") {
|
||||
* @return The matching [Job], or null if not found.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByID(name: String): Job? {
|
||||
return registry[name]
|
||||
fun getByID(name: String?): Job? {
|
||||
return name?.let { registry[it] }
|
||||
}
|
||||
|
||||
override fun clear(plugin: LibreforgePlugin) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.willfp.ecojobs.jobs
|
||||
|
||||
import com.willfp.ecojobs.api.event.PlayerJobJoinEvent
|
||||
import com.willfp.ecojobs.api.event.PlayerJobLeaveEvent
|
||||
import com.willfp.libreforge.toDispatcher
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
@@ -23,6 +24,7 @@ object PriceHandler : Listener {
|
||||
}
|
||||
|
||||
price.pay(player)
|
||||
job.joinEffects?.trigger(player.toDispatcher())
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
@@ -40,5 +42,6 @@ object PriceHandler : Listener {
|
||||
}
|
||||
|
||||
price.pay(player)
|
||||
job.leaveEffects?.trigger(player.toDispatcher())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.willfp.ecojobs.util
|
||||
|
||||
import org.bukkit.OfflinePlayer
|
||||
|
||||
data class LeaderboardCacheEntry(
|
||||
val player: OfflinePlayer,
|
||||
val level: Int
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.willfp.ecojobs.util
|
||||
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
|
||||
class LevelInjectable(
|
||||
level: Int
|
||||
) : PlaceholderInjectable {
|
||||
private val placeholders = listOf(
|
||||
StaticPlaceholder(
|
||||
"level"
|
||||
) { level.toString() }
|
||||
)
|
||||
|
||||
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
|
||||
return placeholders
|
||||
}
|
||||
|
||||
override fun addInjectablePlaceholder(p0: Iterable<InjectablePlaceholder>) {
|
||||
return
|
||||
}
|
||||
|
||||
override fun clearInjectedPlaceholders() {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,13 @@ join-price:
|
||||
# Reference with %join_lore%
|
||||
join-lore: []
|
||||
|
||||
# A list of effects to run when the player joins the job.
|
||||
# Read https://plugins.auxilor.io/effects/configuring-an-effect
|
||||
join-effects:
|
||||
- id: broadcast
|
||||
args:
|
||||
message: "&8» &a%player% &8joined the &6Miner &8job!"
|
||||
|
||||
# The price to leave this job (set to 0 to disable)
|
||||
# Read here for more: https://plugins.auxilor.io/all-plugins/prices
|
||||
leave-price:
|
||||
@@ -39,7 +46,22 @@ leave-price:
|
||||
leave-lore:
|
||||
- " &8» This will cost %leave_price%"
|
||||
|
||||
# The xp requirements for each job level - add new levels by adding more to this list
|
||||
# A list of effects to run when the player leaves the job.
|
||||
# Read https://plugins.auxilor.io/effects/configuring-an-effect
|
||||
leave-effects:
|
||||
- id: send_message
|
||||
args:
|
||||
message: "&8» &8You left the &6Miner &8job!"
|
||||
|
||||
# There are two ways to specify level XP requirements:
|
||||
# 1. A formula to calculate for infinite levels
|
||||
# 2. A list of XP requirements for each level
|
||||
|
||||
# Formula
|
||||
# xp-formula: (2 ^ %level%) * 25
|
||||
# max-level: 100 # The max level of the job
|
||||
|
||||
# List
|
||||
level-xp-requirements:
|
||||
- 100
|
||||
- 120
|
||||
@@ -133,10 +155,13 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks mined"
|
||||
|
||||
# Commands to be sent on levelup, can be formatted two ways:
|
||||
# level:command (e.g. 10:eco give %player% 1000), which would execute that command for level 10
|
||||
# command (e.g. eco give %player% 5000), which would execute that command for all levels
|
||||
level-commands: [ ]
|
||||
# Effects to run when the skill levels up
|
||||
# %level% is the level the skill leveled up to.
|
||||
# If you want to restrict this to certain levels, you can use
|
||||
# require: %level% = 20, or require: %level% < 50, etc.
|
||||
# If you want a reward to run every x levels, you can use
|
||||
# every: 1, or every: 12, etc
|
||||
level-up-effects: [ ]
|
||||
|
||||
# The effects for the job, has %level% as a placeholder
|
||||
effects:
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -95,7 +99,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each bee you breed"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -94,7 +98,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks placed"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -92,7 +96,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each enchanted item"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -107,7 +111,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each crop farmed"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -92,7 +96,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each fish caught"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -104,7 +108,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &7Earn &a$%money%&7 for each log chopped."
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -74,15 +78,17 @@ level-xp-requirements:
|
||||
xp-gain-methods:
|
||||
- trigger: mine_block
|
||||
multiplier: 0.5
|
||||
conditions: [ ]
|
||||
filters:
|
||||
items:
|
||||
- "*wooden_pickaxe"
|
||||
- "*stone_pickaxe"
|
||||
- "*iron_pickaxe"
|
||||
- "*golden_pickaxe"
|
||||
- "*diamond_pickaxe"
|
||||
- "*netherite_pickaxe"
|
||||
filters: [ ]
|
||||
conditions:
|
||||
- id: in_mainhand
|
||||
args:
|
||||
items:
|
||||
- "*wooden_pickaxe"
|
||||
- "*stone_pickaxe"
|
||||
- "*iron_pickaxe"
|
||||
- "*golden_pickaxe"
|
||||
- "*diamond_pickaxe"
|
||||
- "*netherite_pickaxe"
|
||||
|
||||
level-placeholders:
|
||||
- id: "money"
|
||||
@@ -102,21 +108,23 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each &a%blocks%&8 blocks mined"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
args:
|
||||
every: "ceil(10 - %level% / 10)"
|
||||
amount: "0.4 * %level%"
|
||||
filters:
|
||||
items:
|
||||
- "*wooden_pickaxe"
|
||||
- "*stone_pickaxe"
|
||||
- "*iron_pickaxe"
|
||||
- "*golden_pickaxe"
|
||||
- "*diamond_pickaxe"
|
||||
- "*netherite_pickaxe"
|
||||
conditions:
|
||||
- id: in_mainhand
|
||||
args:
|
||||
items:
|
||||
- "*wooden_pickaxe"
|
||||
- "*stone_pickaxe"
|
||||
- "*iron_pickaxe"
|
||||
- "*golden_pickaxe"
|
||||
- "*diamond_pickaxe"
|
||||
- "*netherite_pickaxe"
|
||||
triggers:
|
||||
- mine_block
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -95,7 +99,7 @@ level-up-messages:
|
||||
- "&8» &8Earn &a$%money%&8 per heart of health that"
|
||||
- " &8mobs you kill have"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -10,6 +10,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -17,6 +19,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -92,7 +96,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each smelted item"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -18,6 +18,8 @@ join-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
join-effects: []
|
||||
|
||||
join-lore: []
|
||||
|
||||
leave-price:
|
||||
@@ -25,6 +27,8 @@ leave-price:
|
||||
type: coins
|
||||
display: "&a$%value%"
|
||||
|
||||
leave-effects: []
|
||||
|
||||
leave-lore:
|
||||
- ""
|
||||
|
||||
@@ -133,7 +137,7 @@ level-up-messages:
|
||||
1:
|
||||
- "&8» &8Earn &a$%money%&8 for each tool crafted"
|
||||
|
||||
level-commands: [ ]
|
||||
level-up-effects: [ ]
|
||||
|
||||
effects:
|
||||
- id: give_money
|
||||
|
||||
@@ -8,6 +8,9 @@ messages:
|
||||
needs-player: "&cYou must specify a player!"
|
||||
gave-xp: "&fYou have given &a%xp% &fXP to %player%&f's %job%&f!"
|
||||
reset-xp: "&fYou have reset %player%&f's %job%&f XP!"
|
||||
reset-all-players: "&fYou have reset all players' %job%&f XP!"
|
||||
reset-all-jobs: "&fYou have reset %player%&f's XP for all jobs!"
|
||||
reset-all-players-all-jobs: "&fYou have reset all players' XP for all jobs!"
|
||||
needs-job: "&cYou must specify a job!"
|
||||
need-amount: "&cYou must specify a amount!"
|
||||
invalid-player: "&cInvalid player!"
|
||||
@@ -31,6 +34,9 @@ menu:
|
||||
|
||||
infinity: "∞"
|
||||
|
||||
top-line-format: "%rank%. %player% - %level%"
|
||||
top:
|
||||
name-empty: "&cEmpty"
|
||||
amount-empty: "0"
|
||||
empty-position: "&cN/A"
|
||||
format:
|
||||
- "---- Jobs Leaderboard ----"
|
||||
- "%lines%"
|
||||
@@ -1,5 +1,5 @@
|
||||
#libreforge-updater
|
||||
#Tue Oct 22 12:12:52 BST 2024
|
||||
#Sat Jul 05 16:44:53 BST 2025
|
||||
kotlin.code.style=official
|
||||
libreforge-version=4.72.1
|
||||
version=3.70.1
|
||||
libreforge-version=4.76.1
|
||||
version=3.74.1
|
||||
|
||||
Reference in New Issue
Block a user