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

Merge pull request #2

Added support for _raw and _formatted in the leaderboard placeholders (old placeholders will still work and return formatted value by default)
This commit is contained in:
Will FP
2023-05-02 15:29:30 +01:00
committed by GitHub
13 changed files with 306 additions and 167 deletions

View File

@@ -1,122 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"
}
}
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'maven-publish'
id 'java'
}
dependencies {
implementation project(":eco-core").getSubprojects()
}
allprojects {
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
mavenCentral()
mavenLocal()
maven { url 'https://jitpack.io' }
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
maven { url 'https://repo.codemc.org/repository/nms/' }
maven { url 'https://repo.codemc.io/repository/maven-public/' }
maven { url 'https://repo.dmulloy2.net/repository/public/' }
maven { url 'https://repo.extendedclip.com/content/repositories/placeholderapi/' }
}
jar {
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
}
shadowJar {
}
dependencies {
compileOnly 'com.willfp:eco:6.50.1'
compileOnly 'org.jetbrains:annotations:23.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10'
compileOnly 'me.clip:placeholderapi:2.11.2'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.0'
}
tasks.withType(JavaCompile) {
options.deprecation = true
options.encoding = 'UTF-8'
}
processResources {
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**", "**lang.yml"]) {
expand projectVersion: project.version
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = ['-Xjvm-default=all']
}
}
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean
build.dependsOn shadowJar
}
tasks.withType(Jar) {
destinationDirectory = file("$rootDir/bin/")
}
clean.doLast {
file("${rootDir}/bin").deleteDir()
}
shadowJar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + ".jar"
}
jar {
archiveFileName = findProperty("plugin-name") + " v" + findProperty("version") + " " + "unshaded" + ".jar"
}
group = 'com.willfp'
archivesBaseName = project.name
version = findProperty("version")
compileJava.options.encoding = 'UTF-8'
build.dependsOn shadowJar
build.dependsOn publishToMavenLocal
task buyThePlugins {
dependsOn subprojects.build
doLast {
println 'If you like the plugin, please consider buying it on Spigot or Polymart!'
println 'Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/'
println 'Polymart: https://polymart.org/user/auxilor.1107/'
println 'Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.'
}
}
build.finalizedBy buyThePlugins

123
build.gradle.kts Normal file
View File

@@ -0,0 +1,123 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
}
}
plugins {
id("java-library")
id("com.github.johnrengelman.shadow") version "7.0.0"
id("maven-publish")
id("java")
}
dependencies {
implementation(project(":eco-core"))
implementation(project(":eco-core:core-plugin"))
}
allprojects {
apply(plugin = "java")
apply(plugin = "kotlin")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
repositories {
mavenCentral()
mavenLocal()
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("https://repo.codemc.org/repository/nms/") }
maven { url = uri("https://repo.codemc.io/repository/maven-public/") }
maven { url = uri("https://repo.dmulloy2.net/repository/public/") }
maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") }
}
dependencies {
compileOnly("com.willfp:eco:6.53.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.7.10")
compileOnly("me.clip:placeholderapi:2.11.2")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.1.0")
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
jvmTarget = "17"
}
}
tasks {
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
compileJava {
options.encoding = "UTF-8"
dependsOn(clean)
}
processResources {
filesMatching(listOf("**plugin.yml")) {
expand(mapOf("projectVersion" to project.version))
}
}
build {
dependsOn("shadowJar")
}
}
}
group = "com.willfp"
version = findProperty("version")!!
tasks.register("buyThePlugins") {
doLast {
println("If you like the plugin, please consider buying it on Spigot or Polymart!")
println("Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/")
println("Polymart: https://polymart.org/user/auxilor.1107/")
println("Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.")
}
}
tasks {
build {
dependsOn("publishToMavenLocal")
finalizedBy("buyThePlugins")
}
withType<Jar> {
destinationDirectory.set(file("$rootDir/bin/"))
}
register("cleanBin") {
doLast {
file("$rootDir/bin").deleteRecursively()
}
}
clean {
finalizedBy("cleanBin")
}
named<ShadowJar>("shadowJar") {
archiveFileName.set("${findProperty("plugin-name")} v${findProperty("version")}.jar")
}
named<Jar>("jar") {
archiveFileName.set("${findProperty("plugin-name")} v${findProperty("version")} unshaded.jar")
}
}

View File

@@ -1,2 +0,0 @@
group 'com.willfp'
version rootProject.version

View File

@@ -0,0 +1,2 @@
group = "com.willfp"
version = rootProject.version

View File

@@ -1,19 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
}
build.dependsOn publishToMavenLocal
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}

View File

@@ -0,0 +1,23 @@
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly("org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT")
compileOnly("com.github.MilkBowl:VaultAPI:1.7")
compileOnly(fileTree("../../lib") { include("*.jar") })
}
tasks {
build {
dependsOn("publishToMavenLocal")
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -0,0 +1,103 @@
package com.willfp.ecobits.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecobits.currencies.Currencies
import com.willfp.ecobits.currencies.Currency
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class DynamicCurrencyCommand(
plugin: EcoPlugin,
label: String,
val currency: Currency
): PluginCommand(
plugin,
label,
"ecobits.command.${currency.id}",
false
) {
init {
DynamicCurrencySubcommand.allCommands.forEach {
this.addSubcommand(
DynamicCurrencySubcommand(plugin, it, currency)
)
}
}
override fun onExecute(sender: CommandSender, args: MutableList<String>) {
sender.sendMessage(this.plugin.langYml.getMessage("invalid-command"))
}
class DynamicCurrencySubcommand(
plugin: EcoPlugin,
val command: String,
val currency: Currency
): Subcommand(
plugin,
command,
"ecobits.command.${currency.id}.$command",
false
) {
override fun onExecute(sender: CommandSender, args: MutableList<String>) {
super.onExecute(sender, args)
}
override fun onExecute(sender: Player, args: MutableList<String>) {
val format = when {
currencyCommands.containsIgnoreCase(command) -> currencyFormat
playerCurrencyCommands.containsIgnoreCase(command) -> playerCurrencyFormat
playerCurrencyAmountCommands.containsIgnoreCase(command) -> playerCurrencyAmountFormat
else -> ""
}
Bukkit.dispatchCommand(sender,
format.replace(
"%command%", command
).replace(
"%player%", args.getOrElse(0) { "" }
).replace(
"%amount%", args.getOrElse(1) { "" }
).replace(
"%currency%", currency.id
)
)
}
override fun tabComplete(sender: CommandSender, args: MutableList<String>): MutableList<String> {
return when {
args.size == 1 -> {
if (currencyCommands.containsIgnoreCase(command)) {
StringUtil.copyPartialMatches(args.first(),
Currencies.values().map { it.id }, mutableListOf())
} else {
StringUtil.copyPartialMatches(args.first(),
Bukkit.getOnlinePlayers().map { it.name }, mutableListOf())
}
}
args.size == 2 && !currencyCommands.containsIgnoreCase(command) -> {
StringUtil.copyPartialMatches(args.first(),
Currencies.values().map { it.id }, mutableListOf())
}
else -> mutableListOf()
}
}
companion object {
val currencyCommands = listOf("balance")
val playerCurrencyCommands = listOf("get", "reset")
val playerCurrencyAmountCommands = listOf("give", "givesilent", "pay", "set", "take", "takesilent")
val allCommands = currencyCommands + playerCurrencyCommands + playerCurrencyAmountCommands
val currencyFormat = "ecobits %command% %currency%"
val playerCurrencyFormat = "ecobits %command% %player% %currency%"
val playerCurrencyAmountFormat = "ecobits %command% %player% %currency% %amount%"
}
}
}

View File

@@ -2,7 +2,6 @@
package com.willfp.ecobits.currencies package com.willfp.ecobits.currencies
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Caffeine
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKey
@@ -10,13 +9,13 @@ import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile import com.willfp.eco.core.data.profile
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.placeholder.DynamicPlaceholder import com.willfp.eco.core.placeholder.DynamicPlaceholder
import com.willfp.eco.core.placeholder.PlayerDynamicPlaceholder
import com.willfp.eco.core.placeholder.PlayerPlaceholder import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
import com.willfp.eco.core.price.Prices import com.willfp.eco.core.price.Prices
import com.willfp.eco.util.savedDisplayName import com.willfp.eco.util.savedDisplayName
import com.willfp.eco.util.toNiceString import com.willfp.eco.util.toNiceString
import com.willfp.ecobits.EcoBitsPlugin import com.willfp.ecobits.EcoBitsPlugin
import com.willfp.ecobits.commands.DynamicCurrencyCommand
import com.willfp.ecobits.integrations.IntegrationVault import com.willfp.ecobits.integrations.IntegrationVault
import net.milkbowl.vault.economy.Economy import net.milkbowl.vault.economy.Economy
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -24,6 +23,7 @@ import org.bukkit.OfflinePlayer
import org.bukkit.plugin.ServicePriority import org.bukkit.plugin.ServicePriority
import java.text.DecimalFormat import java.text.DecimalFormat
import java.time.Duration import java.time.Duration
import java.util.Optional
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.log10 import kotlin.math.log10
@@ -34,13 +34,14 @@ class Currency(
val plugin: EcoBitsPlugin, val plugin: EcoBitsPlugin,
val config: Config val config: Config
) { ) {
val leaderBoardCache: Cache<Int, LeaderboardCacheEntry?> = Caffeine.newBuilder() val leaderboardCache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofSeconds(plugin.configYml.getInt("cache-expire-after").toLong())) .expireAfterWrite(Duration.ofSeconds(plugin.configYml.getInt("cache-expire-after").toLong()))
.build() .build<Int, Optional<LeaderboardPlace>>()
val default = config.getDouble("default") val default = config.getDouble("default")
val name = config.getFormattedString("name") val name = config.getFormattedString("name")
val max = config.getDouble("max").let { if (it < 0) Double.MAX_VALUE else it } val max = config.getDouble("max").let { if (it < 0) Double.MAX_VALUE else it }
val isPayable = config.getBool("payable") val isPayable = config.getBool("payable")
@@ -51,42 +52,61 @@ class Currency(
val isLocal = config.getBool("local") val isLocal = config.getBool("local")
val commands = config.getStrings("commands").map { DynamicCurrencyCommand(plugin, it, this) }
val key = PersistentDataKey( val key = PersistentDataKey(
plugin.createNamespacedKey(if (isLocal) "${plugin.serverID}_${id}" else id), plugin.createNamespacedKey(if (isLocal) "${plugin.serverID}_${id}" else id),
PersistentDataKeyType.DOUBLE, PersistentDataKeyType.DOUBLE,
default default
) )
fun getTop(place: Int): LeaderboardCacheEntry? { fun getLeaderboardPlace(place: Int): LeaderboardPlace? {
return leaderBoardCache.get(place) { return leaderboardCache.get(place) {
val top = Bukkit.getOfflinePlayers() val top = Bukkit.getOfflinePlayers()
.sortedByDescending { it.getBalance(this) }.getOrNull(place - 1) .sortedByDescending { it.getBalance(this) }.getOrNull(place - 1)
if (top == null) { if (top == null) {
null Optional.empty()
} else LeaderboardCacheEntry(top, top.getBalance(this)) } else Optional.of(LeaderboardPlace(top, top.getBalance(this)))
}.orElse(null)
}
fun registerCommands() {
this.commands.forEach {
println("Registered ${it.name}")
it.register()
} }
} }
fun unregisterCommands() {
this.commands.forEach { it.unregister() }
}
init { init {
PlaceholderManager.registerPlaceholder( PlaceholderManager.registerPlaceholder(
DynamicPlaceholder( DynamicPlaceholder(
plugin, plugin,
Pattern.compile("top_${id}_[0-9]+_[a-z]+"), Pattern.compile("top_${id}_[0-9]+_[a-z]+_?[a-z]*"),
) { ) { value ->
value ->
val place = value.split("_").getOrNull(2) val place = value.split("_").getOrNull(2)
?.toIntOrNull() ?: return@DynamicPlaceholder "Invalid place" ?.toIntOrNull() ?: return@DynamicPlaceholder ""
val type = value.split("_").getOrNull(3) val type = value.split("_").getOrNull(3)
?: return@DynamicPlaceholder "Type required" ?: return@DynamicPlaceholder ""
return@DynamicPlaceholder when(type) {
"name" -> this.getTop(place)?.player?.savedDisplayName val raw = value.split("_").getOrNull(4)
?.equals("raw", true) ?: true
val placeObj = getLeaderboardPlace(place)
return@DynamicPlaceholder when (type) {
"name" -> placeObj?.player?.savedDisplayName
?: plugin.langYml.getFormattedString("top.name-empty") ?: plugin.langYml.getFormattedString("top.name-empty")
"amount" -> this.getTop(place)?.amount?.formatWithExtension() "amount" -> (if (raw) placeObj?.amount.toNiceString() else placeObj?.amount?.formatWithExtension())
?: plugin.langYml.getFormattedString("top.amount-empty") ?: plugin.langYml.getFormattedString("top.amount-empty")
else -> "Invalid type" else -> ""
} }
} }
) )
@@ -137,10 +157,16 @@ class Currency(
ServicePriority.Highest ServicePriority.Highest
) )
} }
this.unregisterCommands()
this.registerCommands()
} }
} }
data class LeaderboardCacheEntry(val player: OfflinePlayer, val amount: Double) data class LeaderboardPlace(
val player: OfflinePlayer,
val amount: Double
)
fun Double.formatWithExtension(): String { fun Double.formatWithExtension(): String {
val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E') val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')

View File

@@ -27,3 +27,6 @@ currencies:
decimal: true # If decimal amounts are allowed rather than just integer amounts decimal: true # If decimal amounts are allowed rather than just integer amounts
vault: false # If this currency should be registered with vault vault: false # If this currency should be registered with vault
local: false # If this currency should not sync between servers local: false # If this currency should not sync between servers
commands: # A list of commands dedicated to this currency (for easier paying, checking balance, etc)
- crystals
- ecocrystals

View File

@@ -5,6 +5,8 @@ messages:
invalid-command: "&cUnknown subcommand!" invalid-command: "&cUnknown subcommand!"
reloaded: "Reloaded!" reloaded: "Reloaded!"
must-specify-player: "&cYou must specify a player!"
invalid-player: "&cInvalid player!"
must-specify-currency: "&cYou must specify a currency!" must-specify-currency: "&cYou must specify a currency!"
invalid-currency: "&cInvalid currency!" invalid-currency: "&cInvalid currency!"
must-specify-amount: "&cYou must specify an amount!" must-specify-amount: "&cYou must specify an amount!"

View File

@@ -1,2 +1,2 @@
version = 1.4.0 version = 1.5.0
plugin-name = EcoBits plugin-name = EcoBits

View File

@@ -1,5 +0,0 @@
rootProject.name = 'EcoBits'
// Core
include ':eco-core'
include ':eco-core:core-plugin'

5
settings.gradle.kts Normal file
View File

@@ -0,0 +1,5 @@
rootProject.name = "EcoBits"
// Core
include(":eco-core")
include(":eco-core:core-plugin")