diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 52e7dec..0000000 --- a/build.gradle +++ /dev/null @@ -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 diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..0454ba7 --- /dev/null +++ b/build.gradle.kts @@ -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 { + options.encoding = "UTF-8" + } + + tasks.withType { + 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 { + destinationDirectory.set(file("$rootDir/bin/")) + } + + register("cleanBin") { + doLast { + file("$rootDir/bin").deleteRecursively() + } + } + + clean { + finalizedBy("cleanBin") + } + + named("shadowJar") { + archiveFileName.set("${findProperty("plugin-name")} v${findProperty("version")}.jar") + } + + named("jar") { + archiveFileName.set("${findProperty("plugin-name")} v${findProperty("version")} unshaded.jar") + } +} diff --git a/eco-core/build.gradle b/eco-core/build.gradle deleted file mode 100644 index 2f7415f..0000000 --- a/eco-core/build.gradle +++ /dev/null @@ -1,2 +0,0 @@ -group 'com.willfp' -version rootProject.version diff --git a/eco-core/build.gradle.kts b/eco-core/build.gradle.kts new file mode 100644 index 0000000..5f8f296 --- /dev/null +++ b/eco-core/build.gradle.kts @@ -0,0 +1,2 @@ +group = "com.willfp" +version = rootProject.version diff --git a/eco-core/core-plugin/build.gradle b/eco-core/core-plugin/build.gradle deleted file mode 100644 index 08fcd9e..0000000 --- a/eco-core/core-plugin/build.gradle +++ /dev/null @@ -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) - } - } -} diff --git a/eco-core/core-plugin/build.gradle.kts b/eco-core/core-plugin/build.gradle.kts new file mode 100644 index 0000000..c7ecbea --- /dev/null +++ b/eco-core/core-plugin/build.gradle.kts @@ -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("maven") { + from(components["java"]) + } + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/commands/DynamicCurrencyCommand.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/commands/DynamicCurrencyCommand.kt new file mode 100644 index 0000000..bdc9f0b --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/commands/DynamicCurrencyCommand.kt @@ -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) { + 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) { + super.onExecute(sender, args) + } + + override fun onExecute(sender: Player, args: MutableList) { + 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): MutableList { + 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%" + } + } +} \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/currencies/Currency.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/currencies/Currency.kt index d7d8923..e995d6a 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/currencies/Currency.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecobits/currencies/Currency.kt @@ -2,7 +2,6 @@ package com.willfp.ecobits.currencies -import com.github.benmanes.caffeine.cache.Cache import com.github.benmanes.caffeine.cache.Caffeine import com.willfp.eco.core.config.interfaces.Config 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.integrations.placeholder.PlaceholderManager 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.PlayerlessPlaceholder import com.willfp.eco.core.price.Prices import com.willfp.eco.util.savedDisplayName import com.willfp.eco.util.toNiceString import com.willfp.ecobits.EcoBitsPlugin +import com.willfp.ecobits.commands.DynamicCurrencyCommand import com.willfp.ecobits.integrations.IntegrationVault import net.milkbowl.vault.economy.Economy import org.bukkit.Bukkit @@ -24,6 +23,7 @@ import org.bukkit.OfflinePlayer import org.bukkit.plugin.ServicePriority import java.text.DecimalFormat import java.time.Duration +import java.util.Optional import java.util.regex.Pattern import kotlin.math.floor import kotlin.math.log10 @@ -34,13 +34,14 @@ class Currency( val plugin: EcoBitsPlugin, val config: Config ) { - val leaderBoardCache: Cache = Caffeine.newBuilder() + val leaderboardCache = Caffeine.newBuilder() .expireAfterWrite(Duration.ofSeconds(plugin.configYml.getInt("cache-expire-after").toLong())) - .build() + .build>() val default = config.getDouble("default") val name = config.getFormattedString("name") + val max = config.getDouble("max").let { if (it < 0) Double.MAX_VALUE else it } val isPayable = config.getBool("payable") @@ -51,42 +52,61 @@ class Currency( val isLocal = config.getBool("local") + val commands = config.getStrings("commands").map { DynamicCurrencyCommand(plugin, it, this) } + val key = PersistentDataKey( plugin.createNamespacedKey(if (isLocal) "${plugin.serverID}_${id}" else id), PersistentDataKeyType.DOUBLE, default ) - fun getTop(place: Int): LeaderboardCacheEntry? { - return leaderBoardCache.get(place) { + fun getLeaderboardPlace(place: Int): LeaderboardPlace? { + return leaderboardCache.get(place) { val top = Bukkit.getOfflinePlayers() .sortedByDescending { it.getBalance(this) }.getOrNull(place - 1) if (top == null) { - null - } else LeaderboardCacheEntry(top, top.getBalance(this)) + Optional.empty() + } 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 { PlaceholderManager.registerPlaceholder( DynamicPlaceholder( plugin, - Pattern.compile("top_${id}_[0-9]+_[a-z]+"), - ) { - value -> + Pattern.compile("top_${id}_[0-9]+_[a-z]+_?[a-z]*"), + ) { value -> val place = value.split("_").getOrNull(2) - ?.toIntOrNull() ?: return@DynamicPlaceholder "Invalid place" + ?.toIntOrNull() ?: return@DynamicPlaceholder "" + val type = value.split("_").getOrNull(3) - ?: return@DynamicPlaceholder "Type required" - return@DynamicPlaceholder when(type) { - "name" -> this.getTop(place)?.player?.savedDisplayName + ?: return@DynamicPlaceholder "" + + 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") - "amount" -> this.getTop(place)?.amount?.formatWithExtension() + "amount" -> (if (raw) placeObj?.amount.toNiceString() else placeObj?.amount?.formatWithExtension()) ?: plugin.langYml.getFormattedString("top.amount-empty") - else -> "Invalid type" + else -> "" } } ) @@ -137,10 +157,16 @@ class Currency( 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 { val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E') diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml index 772f2f1..22924e5 100644 --- a/eco-core/core-plugin/src/main/resources/config.yml +++ b/eco-core/core-plugin/src/main/resources/config.yml @@ -27,3 +27,6 @@ currencies: decimal: true # If decimal amounts are allowed rather than just integer amounts vault: false # If this currency should be registered with vault 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 diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml index 511bc49..df1aeb1 100644 --- a/eco-core/core-plugin/src/main/resources/lang.yml +++ b/eco-core/core-plugin/src/main/resources/lang.yml @@ -5,6 +5,8 @@ messages: invalid-command: "&cUnknown subcommand!" reloaded: "Reloaded!" + must-specify-player: "&cYou must specify a player!" + invalid-player: "&cInvalid player!" must-specify-currency: "&cYou must specify a currency!" invalid-currency: "&cInvalid currency!" must-specify-amount: "&cYou must specify an amount!" diff --git a/gradle.properties b/gradle.properties index 62ab435..5583e51 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version = 1.4.0 +version = 1.5.0 plugin-name = EcoBits diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index feaf73e..0000000 --- a/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -rootProject.name = 'EcoBits' - -// Core -include ':eco-core' -include ':eco-core:core-plugin' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..6e37a6f --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,5 @@ +rootProject.name = "EcoBits" + +// Core +include(":eco-core") +include(":eco-core:core-plugin")