commit eef049f70fc800c6a35b7df5d4afc7855fe0c59d Author: Hamza Ali Date: Wed Jan 6 07:03:40 2021 +0700 Initial commit: port from svn diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..ce09242 Binary files /dev/null and b/.DS_Store differ diff --git a/compile.bat b/compile.bat new file mode 100644 index 0000000..9fe910e --- /dev/null +++ b/compile.bat @@ -0,0 +1 @@ +mvn package && start ../speak.vbs \ No newline at end of file diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..b7efa9f --- /dev/null +++ b/compile.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +mvn package +mv target/MDRanks-1.0.jar ~/server/plugins/ + +say up \ No newline at end of file diff --git a/libs/.DS_Store b/libs/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/libs/.DS_Store differ diff --git a/libs/Paperclip.jar b/libs/Paperclip.jar new file mode 100644 index 0000000..89b40ed Binary files /dev/null and b/libs/Paperclip.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b730e08 --- /dev/null +++ b/pom.xml @@ -0,0 +1,132 @@ + + + 4.0.0 + + pw.hamzantal + MDRanks + 1.0 + jar + + MDRanks + + MDranks Plugin created by hhhapz + + UTF-8 + 1.3.71 + 1.8 + official + + + https://hamzantal.pw + + + src/main/kotlin + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + false + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + + + + + src/main/resources + true + + + + + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + + + jitpack.io + https://jitpack.io + + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + compile + + + com.github.hazae41 + mc-kutils + master-SNAPSHOT + compile + + + com.destroystokyo.paper + paper-api + 1.8.8-R0.1-SNAPSHOT + system + ${project.basedir}/libs/Paperclip.jar + + + me.clip + placeholderapi + 2.10.5 + provided + + + com.github.MilkBowl + VaultAPI + 1.7 + provided + + + net.luckperms + api + 5.0 + provided + + + + diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..05f6738 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000..03d29eb Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/kotlin/.DS_Store b/src/main/kotlin/.DS_Store new file mode 100644 index 0000000..368bf1d Binary files /dev/null and b/src/main/kotlin/.DS_Store differ diff --git a/src/main/kotlin/pw/.DS_Store b/src/main/kotlin/pw/.DS_Store new file mode 100644 index 0000000..01c3ab2 Binary files /dev/null and b/src/main/kotlin/pw/.DS_Store differ diff --git a/src/main/kotlin/pw/hamzantal/mdranks/Configs.kt b/src/main/kotlin/pw/hamzantal/mdranks/Configs.kt new file mode 100644 index 0000000..703c88a --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/Configs.kt @@ -0,0 +1,255 @@ +package pw.hamzantal.mdranks + +import hazae41.minecraft.kutils.bukkit.ConfigFile +import hazae41.minecraft.kutils.bukkit.keys +import hazae41.minecraft.kutils.get +import org.bukkit.ChatColor +import org.bukkit.configuration.ConfigurationSection +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.api.RankType +import pw.hamzantal.mdranks.api.Vault +import kotlin.math.floor +import kotlin.random.Random +import kotlin.random.nextInt + +object Config : ConfigFile(MDRanks.pl.dataFolder["config.yml"]) { + + val codes = listOf( + 7 to "S", + 6 to "Q", + 5 to "q", + 4 to "T", + 3 to "B", + 2 to "M", + 1 to "K" + ) + + fun formatC(amount: Number): String { + var base: Number = amount.toLong() + var exponent = 0 + while (base.toLong() > 1000) { + base = if (base.toLong() < 1_000_000) base.toDouble() / 1000 + else base.toLong() / 1000 + exponent++ + } + val (_, suffix) = codes.firstOrNull { it.first <= exponent } ?: 0 to "" + + return config.getString("currencyFormat").replace("%amt%", "${floor(base.toDouble() * 10.0) / 10}$suffix") + } + + fun wBrcks(msg: String): String { + return config.getString("bracketformat", "&7[%display%&7]").replace("%display%", msg).c + } + + val defaultPrestige by string("default_prestige") + val defaultRebirth by string("default_rebirth") +} + + + +object Ranks : ConfigFile(MDRanks.pl.dataFolder["ranks.yml"]) { + init { + autoSave = true + minDelay = 1000 + } + + data class PlayerRank(val name: String, val regular: Int, val prestige: Int, val rebirth: Int) + + private const val cacheTime = 1000 * 60 * 5 //calculate top every 5 mins + private var nextCalculate = 0L + private var topCache = listOf() + val top: List get() { + if (nextCalculate < System.currentTimeMillis()) { + topCache = config.keys.map { + PlayerRank( + config.getString("$it.name"), + config.getInt("$it.regular"), + config.getInt("$it.prestige"), + config.getInt("$it.rebirth") + ) + }.sortedWith(compareBy(PlayerRank::rebirth, PlayerRank::prestige, PlayerRank::regular)) + .reversed() + .take(10) + nextCalculate = System.currentTimeMillis() + cacheTime + } + return topCache + } + + operator fun set(p: Player, path: String, value: Int) { + this["${p.uniqueId}.$path"] = value + this["${p.uniqueId}.name"] = p.name + } +} + +val String.wBrackets: String get() = Config.wBrcks(this) + +open class RankData( + val level: Int, + val isLast: Boolean, + val display: String, + val cost: Double, + val commandsOnUpgrade: List, + val broadcast: List, + val msg: List, + val addPerms: List, + val delPerms: List, + val others: ConfigurationSection +) { + val randomCommandList: List + get() { + val sec = others.getConfigurationSection("randomcmds") ?: return listOf() + val chancePair = sec.getKeys(false) + .map { sec.getInt("$it.chance") to sec.getStringList("$it.commands") } + + val max = chancePair.sumBy { it.first } + val choice = Random.nextInt(1..max) + var total = 0 + return chancePair.first { + total += it.first + total >= choice + }.second + } + + fun cost(p: Player): Double { + var calcCost = cost.toDouble() + calcCost *= 1 + (RegularConfig(Perms.reg(p)).percentageIncrease / 100.0) + if (Perms.prestige(p) != 0) + calcCost *= 1 + (PrestigeConfig(Perms.prestige(p)).percentageIncrease / 100.0) + if (Perms.rebirth(p) != 0) + calcCost *= 1 + (RebirthConfig(Perms.rebirth(p)).percentageIncrease / 100.0) + return calcCost + } + + val percentageIncrease: Double get() = others.getDouble("cost_percentage_increase", 0.0) + + override fun toString() = + "RankData(level=$level, display='$display', cost=$cost, commandsOnUpgrade=$commandsOnUpgrade, broadcast=$broadcast, msg=$msg, addPerms=$addPerms, delPerms=$delPerms)" + +} + +abstract class PrisonConfig(fName: String) : ConfigFile(MDRanks.pl.dataFolder["$fName.yml"]) { + + fun nextPcnt(p: Player, type: RankType): Double { + val current = this(p, type) + if (current?.isLast == true) return 0.0 + val data = this(current?.level ?: 0 + 1) + return Vault.balance(p) / data.cost(p) + } + + fun next(p: Player, type: RankType, block: RankData.() -> String): String { + val current = this(p, type) + if (current?.isLast == true) return when (type) { + RankType.REG -> "&euse /prestige!" + RankType.PRESTIGE -> "&euse /rebirth!" + RankType.REBIRTH -> "&eNo more rebirths!" + } + return this(current?.level ?: 0 + 1).block() + } + + operator fun invoke(p: Player, type: RankType): RankData? { + val level = Perms.rankFor(p, type) + return if (level == 0) null + else this(level) + } + + operator fun invoke(level: Int): RankData { + val sec = this.config.getConfigurationSection("$level") ?: run { + throw IllegalStateException("The specified level ($level) does not exist.") + } + val index = config.keys.indexOf("$level") + val last = index + 1 == config.keys.size + return RankData( + level, + last, + sec.getString("display", "").c, + sec.getDouble("cost", 0.0), + sec.getStringList("commands").c, + sec.getStringList("broadcast").c, + sec.getStringList("msg").c, + sec.getStringList("addpermission").c, + sec.getStringList("delpermission").c, + sec + ) + } + + fun max() = config.getKeys(false).last().toInt() + + init { + val cFile = MDRanks.pl.dataFolder["$fName.yml"] + if (!cFile.exists()) { + cFile.createNewFile() + } + } +} + +object RegularConfig : PrisonConfig("regular") { + init { + val cFile = MDRanks.pl.dataFolder["regular.yml"] + if (!cFile.exists()) { + cFile.createNewFile() + set("1.display", "&1A") + set("1.cost", 0) + set("1.addpermission", listOf("essentials.warp.1")) + set("2.display", "&2A") + set("2.cost", 25000) + set( + "2.commands", + listOf( + "[console] give %player% diamond 1", + "[op] say i am executing this command as an operator", + "[player] warp %rankup%" + ) + ) + set("2.broadcast", listOf("&7%player% &eranked up to &7%rankup%", "&7-----------------")) + set("2.msg", listOf("&9You got &b1 &bdiamond.")) + set("2.randomcmds.1.chance", 70) + set("2.randomcmds.1.commands", listOf("[console] tell %player% this was executed 70% of the time")) + set("2.randomcmds.2.chance", 30) + set("2.randomcmds.2.commands", listOf("[console] tell %player% this was executed 30% of the time")) + set("2.addpermission", listOf("essentials.warp.2")) + set("2.delpermission", listOf("essentials.warp.1")) + } + } +} + +object PrestigeConfig : PrisonConfig("prestige") { + init { + val cFile = MDRanks.pl.dataFolder["prestige.yml"] + if (!cFile.exists()) { + cFile.createNewFile() + set("1.display", "&1P1") + set("1.cost", 25000) + set("1.commands", listOf("[console] give %player% diamond 5")) + set("1.broadcast", listOf("&7%player% &eprestiged up to &7%rankup%", "&7-----------------")) + set("1.msg", listOf("&9You got &b5 &bdiamonds.")) + set("1.cost_percentage_increase", 25) + + set("2.display", "&2P2") + set("2.cost", 50000) + set("2.commands", listOf("[console] give %player% gold_ingot 10")) + set("2.broadcast", listOf("&7%player% &eprestiged up to &7%rankup%", "&7-----------------")) + set("2.msg", listOf("&9You got &b10 &6gold ingots.")) + set("2.cost_percentage_increase", 30) + } + } +} + +object RebirthConfig : PrisonConfig("rebirth") { + init { + val cFile = MDRanks.pl.dataFolder["rebirth.yml"] + if (!cFile.exists()) { + cFile.createNewFile() + set("1.display", "&1&lR1") + set("1.cost", 100000) + set("1.commands", listOf("[console] give %player% diamond 64")) + set("1.broadcast", listOf("&7&l%player% &e&lprestiged up to &7&l%rankup%", "&7-----------------")) + set("1.msg", listOf("&9You got &b5 &bdiamonds.")) + set("1.cost_percentage_increase", 25) + set("1.cost_percentage_increase", 25) + } + } +} + +val String.c: String get() = ChatColor.translateAlternateColorCodes('&', this) +val List.c: List get() = map { it.c } \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/MDRanks.kt b/src/main/kotlin/pw/hamzantal/mdranks/MDRanks.kt new file mode 100644 index 0000000..fb190ca --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/MDRanks.kt @@ -0,0 +1,105 @@ +package pw.hamzantal.mdranks + +import hazae41.minecraft.kutils.bukkit.BukkitPlugin +import hazae41.minecraft.kutils.bukkit.command +import hazae41.minecraft.kutils.bukkit.listen +import hazae41.minecraft.kutils.bukkit.msg +import hazae41.minecraft.kutils.get +import org.bukkit.Bukkit +import org.bukkit.entity.Player +import org.bukkit.event.player.PlayerJoinEvent +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.api.RankType +import pw.hamzantal.mdranks.api.Vault +import pw.hamzantal.mdranks.commands.checkBalance +import pw.hamzantal.mdranks.commands.onPrestige +import pw.hamzantal.mdranks.commands.onRankUp +import pw.hamzantal.mdranks.commands.onRebirth + +class MDRanks : BukkitPlugin() { + companion object { + lateinit var pl: MDRanks + } + + val ranksFile = dataFolder["ranks.yml"] + + + override fun onEnable() { + pl = this + saveDefaultConfig() + + listen { + val p = it.player + val lvl = Perms.reg(p) + if (lvl == 0) + Vault.updateRank(p, RankType.REG, 1) + + val regLevel = Perms.reg(p) + val prLevel = Perms.prestige(p) + val rbLevel = Perms.rebirth(p) + Ranks[p, "regular"] = regLevel + Ranks[p, "prestige"] = prLevel + Ranks[p, "rebirth"] = rbLevel + } + + command("mdranks") { sender, args -> + if (!sender.hasPermission("mdranks.admin")) { + sender.err("no_access") + return@command + } + if (args.size == 2) { + val (player, toReset) = args + val p = Bukkit.getPlayer(player)?: run { + sender.err("player_not_found") + return@command + } + } + if (args.size < 3) { + sender.err("mdranks_usage") + return@command + } + val (player, type, num) = args + val p = Bukkit.getPlayer(player) ?: run { + sender.err("player_not_found") + return@command + } + val rank = RankType.byArg(type) ?: run { + sender.sendMessage("rank_not_found") + return@command + } + val level = num.toIntOrNull() ?: 0 + + Vault.updateRank(p, rank, level, true) + sender.success( + "update_player_rank_sender", + "player" to p.name, + "rank" to rank.rankName, + "level" to "$level" + ) + p.general( + "update_player_rank_receiver", + "rank" to rank.rankName, + "level" to "$level" + ) + } + command("rankup") { args -> + onRankUp(this, args) + } + command("prestige") { args -> + onPrestige(this, args) + } + command("rebirth") { _ -> + onRebirth(this) + } + command("bal") { args -> checkBalance(this, args) } + command("rebirthtop") { _ -> + msg("&a&m-------&f&m-------&a&m-------&f&m-------&a&m-------&f&m-------&a&m-------") + Ranks.top.forEachIndexed { i, rank -> + msg("&f&l#${i + 1}. &a${rank.name} &8» &7${rank.rebirth} Rebirth${if (rank.rebirth != 1) "s" else ""}") + } + msg("&a&m-------&f&m-------&a&m-------&f&m-------&a&m-------&f&m-------&a&m-------") + } + + if (isPapi) PapiExpansion().register() + } +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/Messages.kt b/src/main/kotlin/pw/hamzantal/mdranks/Messages.kt new file mode 100644 index 0000000..f39a4e1 --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/Messages.kt @@ -0,0 +1,43 @@ +package pw.hamzantal.mdranks + +import hazae41.minecraft.kutils.bukkit.ConfigFile +import hazae41.minecraft.kutils.get + +object Messages : ConfigFile(MDRanks.pl.dataFolder["messages.yml"]) { + + override var minDelay: Long + get() = super.minDelay + set(value) {} + private val errorFormat by lazy { config.getString("error") } + fun error(msg: String, vararg params: Pair): String { + var base = errorFormat.replace("%s", config.getString("error_msgs.$msg", msg)) + params.forEach { (k, v) -> base = base.replace("%$k%", v) } + return base.c + } + + private val generalFormat by lazy { config.getString("general") } + fun general(msg: String, vararg params: Pair): String { + var base = generalFormat.replace("%s", config.getString("general_msgs.$msg", msg)) + params.forEach { (k, v) -> base = base.replace("%$k%", v) } + return base.c + } + + private val successFormat by lazy { config.getString("success") } + fun success(msg: String, vararg params: Pair): String { + var base = successFormat.replace("%s", config.getString("success_msgs.$msg", msg)) + params.forEach { (k, v) -> base = base.replace("%$k%", v) } + return base.c + } + + + init { + if (file == null) throw IllegalStateException("File can't be null") + val file = file!! + if (!file.exists()) { + val messages = MDRanks.pl.getResource("messages.yml").bufferedReader().readLines().joinToString("\n") + file.createNewFile() + file.writeText(messages) + } + } + +} diff --git a/src/main/kotlin/pw/hamzantal/mdranks/PapiExpansion.kt b/src/main/kotlin/pw/hamzantal/mdranks/PapiExpansion.kt new file mode 100644 index 0000000..da705df --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/PapiExpansion.kt @@ -0,0 +1,136 @@ +package pw.hamzantal.mdranks + +import me.clip.placeholderapi.expansion.PlaceholderExpansion +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.api.RankType.* +import pw.hamzantal.mdranks.api.Vault +import kotlin.math.min + +class PapiExpansion : PlaceholderExpansion() { + + override fun getVersion() = MDRanks.pl.description.version ?: "0.9.0" + + override fun getAuthor() = "hhhapz" + + override fun getIdentifier() = "mdranks" + + override fun persist() = true + + override fun canRegister() = true + + override fun onPlaceholderRequest(p: Player?, params: String?): String { + if (p == null) return "UNKNOWN_PLAYER" + if (params == null) return "UNKNOWN_PARAM" + val args = params.split("_", limit = 2) + + if (args.size == 1) { + return when (args.component1()) { + "money" -> Config.formatC(Vault.balance(p)) + "display" -> { + val dp = RegularConfig(p, REG)?.display ?: "" + val pr = PrestigeConfig(p, PRESTIGE)?.display?: Config.defaultPrestige + val rb = PrestigeConfig(p, REBIRTH)?.display?: Config.defaultRebirth + return "$rb $pr $dp" + } + else -> "UNKNOWN_PARAM" + } + } + if (params == "display_brackets") { + val dp = RegularConfig(p, REG)?.display?.wBrackets ?: "" + val pr = PrestigeConfig(p, PRESTIGE)?.display?.wBrackets + ?: Config.defaultPrestige.wBrackets + val rb = PrestigeConfig(p, REBIRTH)?.display?.wBrackets + ?: Config.defaultRebirth.wBrackets + return "$rb $pr $dp" + } + + return when (args.component1()) { + "currentrank" -> return when (args.component2()) { + "name" -> "${Perms.reg(p)}" + "displayname" -> RegularConfig(p, REG)?.display ?: "" + "displayname_brackets" -> RegularConfig(p, REG)?.display?.wBrackets ?: "" + else -> "UNKNOWN_PARAM" + } + + "rankup" -> return when (args.component2()) { + "name" -> RegularConfig.next(p, REG) { "$level" } + "displayname" -> RegularConfig.next(p, REG) { display } + "displayname_brackets" -> RegularConfig.next(p, REG) { display.wBrackets } + "cost" -> RegularConfig.next(p, REG) { "$cost(p)" } + "cost_formatted" -> RegularConfig.next(p, REG) { Config.formatC(cost(p)) } + "percentage" -> String.format("%.1f", min(100.0, RegularConfig.nextPcnt(p, REG) * 100.0)) + "percentage_decimal" -> String.format("%.2f", min(100.0, RegularConfig.nextPcnt(p, REG))) + "percentage_nolimit" -> String.format("%.1f", RegularConfig.nextPcnt(p, REG) * 100.0) + "percentage_decimal_nolimit" -> String.format("%.2f", RegularConfig.nextPcnt(p, REG)) + else -> "UNKNOWN_PARAM" + } + + "prestige" -> return when (args.component2()) { + "name" -> "${Perms.prestige(p)}" + "displayname" -> PrestigeConfig(p, PRESTIGE)?.display ?: Config.defaultPrestige + "displayname_brackets" -> PrestigeConfig(p, PRESTIGE)?.display?.wBrackets ?: Config.defaultPrestige.wBrackets + else -> "UNKNOWN_PARAM" + } + + "nextprestige" -> return when (args.component2()) { + "name" -> PrestigeConfig.next(p, PRESTIGE) { "$level" } + "displayname" -> PrestigeConfig.next(p, PRESTIGE) { display } + "displayname_brackets" -> PrestigeConfig.next(p, PRESTIGE) { display.wBrackets } + "cost" -> PrestigeConfig.next(p, PRESTIGE) { "$cost(p)" } + "cost_formatted" -> PrestigeConfig.next(p, PRESTIGE) { Config.formatC(cost(p)) } + "percentage" -> String.format("%.1f", min(100.0, RegularConfig.nextPcnt(p, PRESTIGE) * 100.0)) + "percentage_decimal" -> String.format("%.2f", min(100.0, RegularConfig.nextPcnt(p, PRESTIGE))) + "percentage_nolimit" -> String.format("%.1f", RegularConfig.nextPcnt(p, PRESTIGE) * 100.0) + "percentage_decimal_nolimit" -> String.format("%.2f", RegularConfig.nextPcnt(p, PRESTIGE)) + else -> "UNKNOWN_PARAM" + } + + "rebirth" -> return when (args.component2()) { + "name" -> "${Perms.rebirth(p)}" + "displayname" -> RebirthConfig(p, REBIRTH)?.display ?: Config.defaultRebirth + "displayname_brackets" -> RebirthConfig(p, REBIRTH)?.display?.wBrackets ?: Config.defaultRebirth.wBrackets + else -> "UNKNOWN_PARAM" + } + + "nextrebirth" -> return when (args.component2()) { + "name" -> RebirthConfig.next(p, REBIRTH) { "$level" } + "displayname" -> RebirthConfig.next(p, REBIRTH) { display } + "displayname_brackets" -> RebirthConfig.next(p, REBIRTH) { display.wBrackets } + "cost" -> RebirthConfig.next(p, REBIRTH) { "$cost(p)" } + "cost_formatted" -> RebirthConfig.next(p, REBIRTH) { Config.formatC(cost(p)) } + "percentage" -> String.format("%.1f", min(100.0, RegularConfig.nextPcnt(p, REBIRTH) * 100.0)) + "percentage_decimal" -> String.format("%.2f", min(100.0, RegularConfig.nextPcnt(p, REBIRTH))) + "percentage_nolimit" -> String.format("%.1f", RegularConfig.nextPcnt(p, REBIRTH) * 100.0) + "percentage_decimal_nolimit" -> String.format("%.2f", RegularConfig.nextPcnt(p, REBIRTH)) + else -> "UNKNOWN_PARAM" + } + + "money" -> return when { + args.component2() == "nonformatted" -> "${Vault.balance(p)}" + else -> "UNKNOWN_PARAM" + } + "next" -> return when (args.component2()) { + "percentage" -> String.format("%.1f", min(100.0, nextPercentage(p) * 100.0)) + "percentage_decimal" -> String.format("%.2f", min(1.0, nextPercentage(p))) + else -> "UNKNOWN_PARAM" + } + else -> "UNKNOWN_PARAM" + } + } + + fun nextPercentage(p: Player): Double { + val bal = Vault.balance(p) + + val reg = RegularConfig(p, REG) ?: throw IllegalStateException("The regular rank data was not found for ${p.name}") + if (!reg.isLast) return bal / RegularConfig(reg.level + 1).cost(p) + + val currentPrestige = PrestigeConfig(p, PRESTIGE)?.level ?: 0 + if (currentPrestige != PrestigeConfig.max()) return bal / PrestigeConfig(currentPrestige + 1).cost(p) + + val currentRebirth = RebirthConfig(p, REBIRTH)?.level ?: 0 + if (currentRebirth != RebirthConfig.max()) return bal / RebirthConfig(currentRebirth + 1).cost(p) + return 100.0 + } + +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/Test.kt b/src/main/kotlin/pw/hamzantal/mdranks/Test.kt new file mode 100644 index 0000000..47a3b35 --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/Test.kt @@ -0,0 +1,10 @@ +package pw.hamzantal.mdranks + +fun main() { + val names = listOf("person a", "p b", "per c", "p e", "asdasdasd") + val size = names.map { it.length }.max()?: 0 + names.forEach { + val name = String.format("%-${size}s >", it) + println(name) + } +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/Util.kt b/src/main/kotlin/pw/hamzantal/mdranks/Util.kt new file mode 100644 index 0000000..81cd57b --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/Util.kt @@ -0,0 +1,40 @@ +package pw.hamzantal.mdranks + +import hazae41.minecraft.kutils.bukkit.msg +import me.clip.placeholderapi.PlaceholderAPI +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.api.RankType +import pw.hamzantal.mdranks.api.Vault + +fun CommandSender.send(message: String) { + msg(message) +} + +val isPapi by lazy { Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null } + +fun String.placeholders(p: Player, data: RankData, cmdPrefix: Boolean = false): String { + val baseReplacement = replace("%player%", p.name) + .replace("%rankup%", "${data.level}") + .replace("%display%", data.display) + .run { + if (cmdPrefix) replaceFirst("[console] ", "") + .replaceFirst("[op] ", "") + .replaceFirst("[player] ", "") + else this + } + return if (isPapi) PlaceholderAPI.setPlaceholders(p, baseReplacement) else baseReplacement +} + +fun CommandSender.err(msg: String, vararg placeholder: Pair) { + msg(Messages.error(msg, *placeholder)) +} + +fun CommandSender.general(msg: String, vararg placeholder: Pair) { + msg(Messages.general(msg, *placeholder)) +} + +fun CommandSender.success(msg: String, vararg placeholder: Pair) { + msg(Messages.success(msg, *placeholder)) +} diff --git a/src/main/kotlin/pw/hamzantal/mdranks/api/Perms.kt b/src/main/kotlin/pw/hamzantal/mdranks/api/Perms.kt new file mode 100644 index 0000000..079cfdd --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/api/Perms.kt @@ -0,0 +1,30 @@ +package pw.hamzantal.mdranks.api + +import net.luckperms.api.LuckPerms +import net.luckperms.api.model.user.User +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.* + +enum class RankType(val rankName: String, val alias: List = listOf(), val config: PrisonConfig) { + REG("regular", listOf("reg", "regular", "rg"), RegularConfig), + PRESTIGE("prestige", listOf("pr", "prestige"), PrestigeConfig), + REBIRTH("rebirth", listOf("rb", "rebirth", "birth"), RebirthConfig); + + companion object { + fun byArg(arg: String) = values().firstOrNull { arg in it.alias } + } +} + +object Perms { + fun rankFor(p: Player, type: RankType): Int { + return p.effectivePermissions + .filter { it.permission.startsWith("mdranks.${type.rankName}.") } + .map { (it.permission.removePrefix("mdranks.${type.rankName}.").toIntOrNull()) ?: 0 } + .max() ?: 0 + } + + fun reg(p: Player) = rankFor(p, RankType.REG) + fun prestige(p: Player) = rankFor(p, RankType.PRESTIGE) + fun rebirth(p: Player) = rankFor(p, RankType.REBIRTH) + +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/api/Vault.kt b/src/main/kotlin/pw/hamzantal/mdranks/api/Vault.kt new file mode 100644 index 0000000..4dc1b12 --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/api/Vault.kt @@ -0,0 +1,65 @@ +package pw.hamzantal.mdranks.api + +import net.milkbowl.vault.economy.Economy +import net.milkbowl.vault.economy.EconomyResponse +import net.milkbowl.vault.permission.Permission +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.MDRanks +import pw.hamzantal.mdranks.Ranks + + +object Vault { + + private val pl = MDRanks.pl + + val econ by lazy { + if (pl.server.pluginManager.getPlugin("Vault") == null) { + throw IllegalStateException("The vault dependency was not found") + } + pl.server.servicesManager.getRegistration(Economy::class.java).provider!! + } + + val perms by lazy { + if (pl.server.pluginManager.getPlugin("Vault") == null) { + throw IllegalStateException("The vault dependency was not found") + } + pl.server.servicesManager.getRegistration(Permission::class.java).provider!! + } + + + fun withdraw(p: Player, amount: Number, onError: EconomyResponse.() -> Unit): Double { + if (!econ.hasAccount(p)) econ.createPlayerAccount(p) + val success = econ.withdrawPlayer(p, amount.toDouble()) + if (!success.transactionSuccess()) { + success.onError() + throw IllegalStateException("Fail on Withdraw: ${success.errorMessage}") + } + return econ.getBalance(p) + } + + fun balance(p: Player) = econ.getBalance(p) + + fun updateRank(p: Player, type: RankType, level: Int, manual: Boolean = false) { + if (level == 0 && type == RankType.REG) { + updateRank(p, type, 1, manual) + return + } + + if (manual) { + val current = Perms.rankFor(p, type) + type.config(current).addPerms.forEach { perms.playerRemove(null, p, it) } + } + + Ranks[p, type.rankName] = level + + p.effectivePermissions + .filter { it.value && it.permission.startsWith("mdranks.${type.rankName}") } + .forEach { perms.playerRemove(null, p, it.permission) } + if (level == 0) return + + val config = type.config(level) + config.addPerms.forEach { perms.playerAdd(null, p, it) } + config.delPerms.forEach { perms.playerRemove(null, p, it) } + perms.playerAdd(null, p, "mdranks.${type.rankName}.$level") + } +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/commands/BalCommand.kt b/src/main/kotlin/pw/hamzantal/mdranks/commands/BalCommand.kt new file mode 100644 index 0000000..860b8a8 --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/commands/BalCommand.kt @@ -0,0 +1,30 @@ +package pw.hamzantal.mdranks.commands + +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.Config +import pw.hamzantal.mdranks.api.Vault +import pw.hamzantal.mdranks.err +import pw.hamzantal.mdranks.general + +fun checkBalance(sender: CommandSender, args: Array) { + if (sender is Player) { + if (args.isEmpty()) { + sender.general("balance_format", "balance" to Config.formatC(Vault.balance(sender))) + return + } + } else { + if (args.isEmpty()) sender.err("You must be a player to use this. /bal [player].") + return + } + val target = Bukkit.getPlayer(args.component1()) ?: sender.run { + this.err("player_not_found") + return + } + sender.general( + "other_balance", + "player" to target.name.toUpperCase(), + "balance" to Config.formatC(Vault.balance(target)) + ) +} diff --git a/src/main/kotlin/pw/hamzantal/mdranks/commands/CommandUtil.kt b/src/main/kotlin/pw/hamzantal/mdranks/commands/CommandUtil.kt new file mode 100644 index 0000000..040f799 --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/commands/CommandUtil.kt @@ -0,0 +1,61 @@ +package pw.hamzantal.mdranks.commands + +import org.bukkit.Bukkit +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.Config +import pw.hamzantal.mdranks.RankData +import pw.hamzantal.mdranks.api.RankType +import pw.hamzantal.mdranks.api.Vault +import pw.hamzantal.mdranks.err +import pw.hamzantal.mdranks.placeholders + +fun rankUpgradePrerequisites(p: Player, next: RankData, type: RankType = RankType.REG): Boolean { + val balance = Vault.balance(p) + val cost = next.cost(p) + if (balance < cost) { + return false + } + Vault.withdraw(p, cost) { + p.err("unknown_error_withdraw", "cost" to Config.formatC(cost)) + } + performUpgradeRank(p, next, type) + return true +} + +fun performUpgradeRank(p: Player, data: RankData, type: RankType) { + Vault.updateRank(p, type, data.level) + if (type == RankType.REBIRTH) { + Vault.updateRank(p, RankType.REG, 1, true) + Vault.updateRank(p, RankType.PRESTIGE, 0, true) + } + + data.commandsOnUpgrade.forEach { + it.executeCommandWithPrefix(p, data) + } + data.broadcast.forEach { + val msg = it.placeholders(p, data) + Bukkit.broadcastMessage(msg) + } + data.msg.forEach { + val msg = it.placeholders(p, data) + p.sendMessage(msg) + } + data.randomCommandList.forEach { + it.executeCommandWithPrefix(p, data) + } +} + +fun String.executeCommandWithPrefix(p: Player, data: RankData) { + val cmd = placeholders(p, data, true) + when { + startsWith("[console]") -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd) + startsWith("[player]") -> p.performCommand(cmd) + startsWith("[op]") -> { + val prev = p.isOp + p.isOp = true + p.performCommand(cmd) + p.isOp = prev + } + else -> throw IllegalStateException("The [commandsOnUpgrade ($this), level (${data.level})] command does not start with a prefix") + } +} \ No newline at end of file diff --git a/src/main/kotlin/pw/hamzantal/mdranks/commands/PrestigeCommand.kt b/src/main/kotlin/pw/hamzantal/mdranks/commands/PrestigeCommand.kt new file mode 100644 index 0000000..c9c328e --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/commands/PrestigeCommand.kt @@ -0,0 +1,66 @@ +package pw.hamzantal.mdranks.commands + +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.Config +import pw.hamzantal.mdranks.PrestigeConfig +import pw.hamzantal.mdranks.RegularConfig +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.api.RankType +import pw.hamzantal.mdranks.err + +fun onPrestige(p: CommandSender, args: Array) { + if (p !is Player) { + p.err("prestige_not_player") + return + } + val regMax = RegularConfig.max() + if (regMax != Perms.reg(p)) { + p.err( + "prestige_not_max_rankup", + "rankup_display" to RegularConfig(regMax).display, + "rankup" to "$regMax" + ) + return + } + + if (args.isNotEmpty() && args.first() == "max") return onPrestigeMax(p) + + val currentLevel = Perms.prestige(p) + if (currentLevel != 0) { + val current = PrestigeConfig(currentLevel) + + if (current.isLast) { + p.err("prestige_max") + return + } + } + + val next = PrestigeConfig(currentLevel + 1) + if (!rankUpgradePrerequisites(p, next, RankType.PRESTIGE)) { + p.err("prestige_not_enough_money", "cost" to Config.formatC(next.cost(p))) + } +} + +fun onPrestigeMax(p: Player) { + val currentLevel = Perms.prestige(p) + if (currentLevel != 0) { + val current = PrestigeConfig(currentLevel) + + if (current.isLast) { + p.err("prestige_max") + return + } + } + var nextLevel = currentLevel + 1 + while (nextLevel <= PrestigeConfig.max()) { + val next = PrestigeConfig(nextLevel) + if (!rankUpgradePrerequisites(p, next, RankType.PRESTIGE)) { + if (nextLevel == currentLevel + 1) + p.err("prestige_not_enough_money", "cost" to Config.formatC(next.cost(p))) + return + } + nextLevel++ + } + +} diff --git a/src/main/kotlin/pw/hamzantal/mdranks/commands/RankupCommand.kt b/src/main/kotlin/pw/hamzantal/mdranks/commands/RankupCommand.kt new file mode 100644 index 0000000..01a558c --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/commands/RankupCommand.kt @@ -0,0 +1,50 @@ +package pw.hamzantal.mdranks.commands + +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.Config +import pw.hamzantal.mdranks.RegularConfig +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.err + +fun onRankUp(p: CommandSender, args: Array) { + if (p !is Player) { + p.err("rankup_not_player") + return + } + if (args.isNotEmpty() && args.first() == "max") return onRankupMax(p) + + val current = RegularConfig(Perms.reg(p)) + if (current.isLast) { + p.err("rankup_max") + return + } + + val next = RegularConfig(current.level + 1) + if (!rankUpgradePrerequisites(p, next)) { + p.err("rankup_not_enough_money", "cost" to Config.formatC(next.cost(p))) + } +} + +fun onRankupMax(p: Player) { + val currentLevel = Perms.reg(p) + val current = RegularConfig(currentLevel) + if (current.isLast) { + p.err("rankup_max") + return + } + + var nextLevel = currentLevel + 1 + while (nextLevel <= RegularConfig.max()) { + val next = RegularConfig(nextLevel) + if (!rankUpgradePrerequisites(p, next)) { + if (nextLevel == currentLevel + 1) + p.err("rankup_not_enough_money", "cost" to Config.formatC(next.cost(p))) + return + } + nextLevel++ + } +} + + + diff --git a/src/main/kotlin/pw/hamzantal/mdranks/commands/RebirthCommand.kt b/src/main/kotlin/pw/hamzantal/mdranks/commands/RebirthCommand.kt new file mode 100644 index 0000000..740ecfd --- /dev/null +++ b/src/main/kotlin/pw/hamzantal/mdranks/commands/RebirthCommand.kt @@ -0,0 +1,48 @@ +package pw.hamzantal.mdranks.commands + +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import pw.hamzantal.mdranks.* +import pw.hamzantal.mdranks.api.Perms +import pw.hamzantal.mdranks.api.RankType + +fun onRebirth(p: CommandSender) { + if (p !is Player) { + p.err("You can only rebirth up as a player") + return + } + val regMax = RegularConfig.max() + if (regMax != Perms.reg(p)) { + p.err( + "rebirth_not_max_rankup", + "rankup_display" to RegularConfig(regMax).display, + "rankup" to "$regMax" + ) + return + } + + val prMax = PrestigeConfig.max() + if (prMax != Perms.prestige(p)) { + p.err( + "rebirth_not_max_prestige", + "prestige_display" to PrestigeConfig(prMax).display, + "prestige" to "$prMax" + ) + return + } + + val currentLevel = Perms.rebirth(p) + if (currentLevel != 0) { + val current = RebirthConfig(currentLevel) + + if (current.isLast) { + p.err("rebirth_max") + return + } + } + + val next = RebirthConfig(currentLevel + 1) + if (!rankUpgradePrerequisites(p, next, RankType.REBIRTH)) { + p.err("rebirth_not_enough_money", "cost" to Config.formatC(next.cost(p))) + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..f26abaa --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,6 @@ +currencyFormat: "$%amt%" + +bracketformat: "&7[%display%&7]" + +default_prestige: "&fR0" +default_rebirth: "&fP0" \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml new file mode 100644 index 0000000..261c2b4 --- /dev/null +++ b/src/main/resources/messages.yml @@ -0,0 +1,35 @@ +error: "&c[!] &7%s" +general: "&7%s" +success: "&a%s" + +error_msgs: + no_access: "You do not have access to this command." + mdranks_usage: "/mdranks [player] [reg|prestige|rebirth] [level]" + player_not_found: "The specified player was not found." + rank_not_found: "The specified rank was not found." +############## + rankup_not_player: "You can only rank up as a player" + rankup_max: "You are at the max level! Use /prestige instead." + rankup_not_enough_money: "You do not have enough money to rankup. The next rankup costs %cost%." +############## + prestige_not_player: "You can only prestige as a player" + prestige_not_max_rankup: "You must be rank %rankup_display% first!" # use rankup_display for max display, or rankup for rankup level (numerical value) + prestige_max: "You are at the max level! Use /rebirth instead." + prestige_not_enough_money: "You do not have enough money to prestige. The next prestige costs %cost%." +############## + rebirth_not_player: "You can only rebirth up as a player" + rebirth_not_max_rankup: "You must be rank %rankup_display% first!" # same placeholder options as prestige_not_max_rankup + rebirth_not_max_prestige: "You must be prestige %prestige_display% first!" # same placeholder options as above, (prestige instead of rankup) + rebirth_max: "You are at the max level!" + rebirth_not_enough_money: "You do not have enough money to rebirth. The next rebirth costs %cost%." +############## + unknown_error_withdraw: "An error occurred while withdrawing %cost%. Ask an administrator if you believe this is an error." + + +general_msgs: + balance_format: "&a&lBALANCE &8» &7%balance%" + other_balance: "&a&lBALANCE OF %player% &8» &7%balance%" + +success_msgs: + update_player_rank_sender: "%player% has been set to %rank% %level%" + update_player_rank_receiver: "You are now %rank% %level%" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..bb3d906 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,20 @@ +name: MDRanks +version: ${project.version} +main: pw.hamzantal.mdranks.MDRanks +api-version: 1.13 +authors: [hhhapz] +depend: [Vault, LuckPerms] +description: MDranks Plugin created by hhhapz +website: https://hamzantal.pw +commands: + mdranks: + rankup: + prestige: + rebirth: + rebirthtop: + aliases: [ranktop, prestigetop] + bal: + aliases: [balance, money] +permissions: + mkdranks.admin: + default: op \ No newline at end of file