diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3d85b4a..5dad1a4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,11 +21,11 @@ jobs: - name: Validate Gradle Wrapper uses: gradle/actions/wrapper-validation@v3 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 17 + java-version: 21 check-latest: true - name: Gradle Properties Import. diff --git a/.gitignore b/.gitignore index cf61736..0868d39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,27 @@ -build .gradle .idea -jars +build -common/build -paper/build +buildSrc/.gradle +buildSrc/build + +core/.gradle +core/build + +api/.gradle api/build -common/.gradle -api/.gradle paper/.gradle +paper/build -paper/run +paper/run/ -!paper/run/config -!paper/run/spigot.yml +!paper/run/config/paper-global.yml +!paper/run/config/paper-world-defaults.yml !paper/run/bukkit.yml !paper/run/eula.txt +!paper/run/ops.json !paper/run/server.properties -!paper/run/plugins -!paper/run/ops.json \ No newline at end of file +!paper/run/spigot.yml + +jars \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ebded6..37fdf1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,2 @@ -## Changes -* Updated the item builder, What does this mean? - * Custom Items are finally supported - * The item sections in the config.yml have the same capabilities as our other plugins. -* All lores, display names have placeholder api support. \ No newline at end of file +### Fixed: +- Caught a few stragglers in the code not yet updated to the using the methods for the new item format. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 722a330..44b196f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,68 @@ plugins { - `root-plugin` + alias(libs.plugins.minotaur) + alias(libs.plugins.hangar) + + `java-plugin` +} + +val buildNumber: String? = System.getenv("BUILD_NUMBER") + +rootProject.version = if (buildNumber != null) "1.4.2-$buildNumber" else "1.4.2" + +val isSnapshot = false + +val content: String = rootProject.file("CHANGELOG.md").readText(Charsets.UTF_8) + +subprojects.filter { it.name != "api" }.forEach { + it.project.version = rootProject.version +} + +modrinth { + token.set(System.getenv("MODRINTH_TOKEN")) + + projectId.set(rootProject.name.lowercase()) + + versionType.set(if (isSnapshot) "beta" else "release") + + versionName.set("${rootProject.name} ${rootProject.version}") + versionNumber.set(rootProject.version as String) + + changelog.set(content) + + uploadFile.set(rootProject.projectDir.resolve("jars/${rootProject.name}-${rootProject.version}.jar")) + + gameVersions.set(listOf(libs.versions.minecraft.get())) + + loaders.addAll("paper", "purpur") + + autoAddDependsOn.set(false) + detectLoaders.set(false) +} + +hangarPublish { + publications.register("plugin") { + apiKey.set(System.getenv("HANGAR_KEY")) + + id.set(rootProject.name.lowercase()) + + version.set(rootProject.version as String) + + channel.set(if (isSnapshot) "Snapshot" else "Release") + + changelog.set(content) + + platforms { + paper { + jar.set(rootProject.projectDir.resolve("jars/${rootProject.name}-${rootProject.version}.jar")) + + platformVersions.set(listOf(libs.versions.minecraft.get())) + + dependencies { + hangar("PlaceholderAPI") { + required = false + } + } + } + } + } } \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 4a318ac..d4e1846 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,14 +1,11 @@ +import com.ryderbelserion.feather.feather + plugins { + id("com.ryderbelserion.feather-logic") version "0.0.1" + `kotlin-dsl` } -repositories { - gradlePluginPortal() - mavenCentral() -} - dependencies { - implementation(libs.paperweight.userdev) - implementation(libs.publishing.modrinth) - implementation(libs.publishing.hangar) + feather("0.0.1") } \ No newline at end of file diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index b5f44b0..523a2cf 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -1,9 +1,23 @@ +rootProject.name = "buildSrc" + dependencyResolutionManagement { - versionCatalogs { - create("libs") { - from(files("../gradle/libs.versions.toml")) - } + repositories { + maven("https://repo.crazycrew.us/releases") + + gradlePluginPortal() + + mavenCentral() } } -rootProject.name = "buildSrc" \ No newline at end of file +pluginManagement { + repositories { + maven("https://repo.crazycrew.us/releases") + + gradlePluginPortal() + } +} + +plugins { + id("com.ryderbelserion.feather-settings") +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/fabric-plugin.gradle.kts b/buildSrc/src/main/kotlin/fabric-plugin.gradle.kts deleted file mode 100644 index ad3acef..0000000 --- a/buildSrc/src/main/kotlin/fabric-plugin.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("root-plugin") -} - -val mcVersion = providers.gradleProperty("mcVersion").get() -val fabricVersion = providers.gradleProperty("version").get() - -project.version = if (System.getenv("BUILD_NUMBER") != null) "$fabricVersion-${System.getenv("BUILD_NUMBER")}" else fabricVersion - -tasks { - modrinth { - loaders.addAll("fabric") - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/java-plugin.gradle.kts b/buildSrc/src/main/kotlin/java-plugin.gradle.kts new file mode 100644 index 0000000..7f0f291 --- /dev/null +++ b/buildSrc/src/main/kotlin/java-plugin.gradle.kts @@ -0,0 +1,46 @@ +import com.ryderbelserion.feather.enums.Repository + +plugins { + id("com.ryderbelserion.feather-core") + + `maven-publish` + + `java-library` +} + +repositories { + maven("https://repo.extendedclip.com/content/repositories/placeholderapi") + + maven("https://repo.codemc.io/repository/maven-public") + + maven("https://repo.oraxen.com/releases") + + maven(Repository.CrazyCrewReleases.url) + + maven(Repository.Jitpack.url) + + flatDir { dirs("libs") } + + mavenCentral() +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +tasks { + compileJava { + options.encoding = Charsets.UTF_8.name() + options.release.set(21) + } + + javadoc { + options.encoding = Charsets.UTF_8.name() + } + + processResources { + filteringCharset = Charsets.UTF_8.name() + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/paper-plugin.gradle.kts b/buildSrc/src/main/kotlin/paper-plugin.gradle.kts index 93979d0..bf7e7f1 100644 --- a/buildSrc/src/main/kotlin/paper-plugin.gradle.kts +++ b/buildSrc/src/main/kotlin/paper-plugin.gradle.kts @@ -1,27 +1,13 @@ +import com.ryderbelserion.feather.enums.Repository + plugins { - id("root-plugin") + id("java-plugin") } repositories { - maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") + maven("https://repo.triumphteam.dev/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") + maven("https://maven.enginehub.org/repo") - maven("https://repo.codemc.io/repository/maven-public/") - - maven("https://repo.triumphteam.dev/snapshots/") - - maven("https://repo.fancyplugins.de/releases/") - - flatDir { dirs("libs") } -} - -val mcVersion = providers.gradleProperty("mcVersion").get() - -project.version = if (System.getenv("BUILD_NUMBER") != null) "${rootProject.version}-${System.getenv("BUILD_NUMBER")}" else rootProject.version - -tasks { - modrinth { - loaders.addAll("paper", "purpur") - } + maven(Repository.Paper.url) } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/root-plugin.gradle.kts b/buildSrc/src/main/kotlin/root-plugin.gradle.kts deleted file mode 100644 index b42ff2d..0000000 --- a/buildSrc/src/main/kotlin/root-plugin.gradle.kts +++ /dev/null @@ -1,93 +0,0 @@ -import io.papermc.hangarpublishplugin.model.Platforms - -plugins { - id("io.papermc.hangar-publish-plugin") - - id("com.modrinth.minotaur") - - `java-library` - - `maven-publish` -} - -base { - archivesName.set(rootProject.name) -} - -repositories { - maven("https://repo.crazycrew.us/snapshots/") - - maven("https://repo.crazycrew.us/releases/") - - maven("https://jitpack.io/") - - mavenCentral() -} - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of("17")) -} - -tasks { - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(17) - } - - javadoc { - options.encoding = Charsets.UTF_8.name() - } - - processResources { - filteringCharset = Charsets.UTF_8.name() - } - - val directory = File("$rootDir/jars/${project.name.lowercase()}") - val mcVersion = providers.gradleProperty("mcVersion").get() - - val isBeta: Boolean = providers.gradleProperty("isBeta").get().toBoolean() - val type = if (isBeta) "Beta" else "Release" - - // Publish to hangar.papermc.io. - hangarPublish { - publications.register("plugin") { - version.set("${project.version}") - - id.set(rootProject.name) - - channel.set(type) - - changelog.set(rootProject.file("CHANGELOG.md").readText(Charsets.UTF_8)) - - apiKey.set(System.getenv("hangar_key")) - - platforms { - register(Platforms.PAPER) { - jar.set(file("$directory/${rootProject.name}-${project.version}.jar")) - - platformVersions.set(listOf(mcVersion)) - } - } - } - } - - modrinth { - versionType.set(type.lowercase()) - - autoAddDependsOn.set(false) - - token.set(System.getenv("modrinth_token")) - - projectId.set(rootProject.name.lowercase()) - - changelog.set(rootProject.file("CHANGELOG.md").readText(Charsets.UTF_8)) - - versionName.set("${rootProject.name} ${project.version}") - - versionNumber.set("${project.version}") - - uploadFile.set("$directory/${rootProject.name}-${project.version}.jar") - - gameVersions.add(mcVersion) - } -} \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts deleted file mode 100644 index 0986fd7..0000000 --- a/common/build.gradle.kts +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - id("root-plugin") -} - -dependencies { - compileOnlyApi(libs.bundles.adventure) - - compileOnly(libs.cluster.api) - - api(libs.configme) { - exclude(group = "org.yaml", module = "snakeyaml") - } -} \ No newline at end of file diff --git a/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyAuctions.java b/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyAuctions.java deleted file mode 100644 index ff3cc2e..0000000 --- a/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyAuctions.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ryderbelserion.crazyauctions; - -import ch.jalu.configme.SettingsManager; -import ch.jalu.configme.SettingsManagerBuilder; -import ch.jalu.configme.resource.YamlFileResourceOptions; -import com.ryderbelserion.crazyauctions.platform.impl.Config; -import com.ryderbelserion.crazyauctions.platform.Server; -import java.io.File; - -public class CrazyAuctions { - - private final Server server; - - private final SettingsManager config; - - public CrazyAuctions(Server server) { - this.server = server; - - - // Create config files - YamlFileResourceOptions builder = YamlFileResourceOptions.builder().indentationSize(2).build(); - - this.config = SettingsManagerBuilder - .withYamlFile(new File(server.getFolder(), "config.yml"), builder) - .useDefaultMigrationService() - .configurationData(Config.class) - .create(); - - // Register provider. - CrazyProvider.register(this); - } - - public void reload() { - // Reload the config. - this.config.reload(); - } - - public void disable() { - // Save the config. - this.config.save(); - - // Unregister provider. - CrazyProvider.unregister(); - } - - public Server getServer() { - return this.server; - } - - public SettingsManager getConfig() { - return this.config; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyProvider.java b/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyProvider.java deleted file mode 100644 index 0675624..0000000 --- a/common/src/main/java/com/ryderbelserion/crazyauctions/CrazyProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ryderbelserion.crazyauctions; - -public final class CrazyProvider { - - private static CrazyAuctions instance; - - private CrazyProvider() { - throw new UnsupportedOperationException("This class cannot be instantiated"); - } - - public static CrazyAuctions get() { - if (instance == null) { - throw new IllegalStateException("CrazyAuctions is not loaded."); - } - - return instance; - } - - static void register(final CrazyAuctions instance) { - if (get() != null) { - return; - } - - CrazyProvider.instance = instance; - } - - static void unregister() { - CrazyProvider.instance = null; - } -} \ No newline at end of file diff --git a/common/src/main/java/com/ryderbelserion/crazyauctions/platform/Server.java b/common/src/main/java/com/ryderbelserion/crazyauctions/platform/Server.java deleted file mode 100644 index 504cc39..0000000 --- a/common/src/main/java/com/ryderbelserion/crazyauctions/platform/Server.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.ryderbelserion.crazyauctions.platform; - -import java.io.File; - -public interface Server { - - File getFolder(); - -} \ No newline at end of file diff --git a/common/src/main/java/com/ryderbelserion/crazyauctions/platform/impl/Config.java b/common/src/main/java/com/ryderbelserion/crazyauctions/platform/impl/Config.java deleted file mode 100644 index 1971c9e..0000000 --- a/common/src/main/java/com/ryderbelserion/crazyauctions/platform/impl/Config.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ryderbelserion.crazyauctions.platform.impl; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.configurationdata.CommentsConfiguration; -import ch.jalu.configme.properties.Property; -import org.jetbrains.annotations.NotNull; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public class Config implements SettingsHolder { - - - @Override - public void registerComments(@NotNull CommentsConfiguration conf) { - String[] header = { - "Support: https://discord.gg/badbones-s-live-chat-182615261403283459", - "Github: https://github.com/Crazy-Crew", - "", - "Issues: https://github.com/Crazy-Crew/CrazyAuctions/issues", - "Features: https://github.com/Crazy-Crew/CrazyAuctions/issues", - "", - "Sounds: https://jd.papermc.io/paper/1.20/org/bukkit/Sound.html", - "Enchantments: https://jd.papermc.io/paper/1.20/org/bukkit/enchantments/Enchantment.html" - }; - - conf.setComment("root", header); - } - - @Comment("Whether you want CrazyAuctions to shut up or not.") - public static final Property verbose_logging = newProperty("root.verbose_logging", true); - - @Comment({ - "Sends anonymous statistics about how the plugin is used to bstats.org.", - "bstats is a service for plugin developers to find out how the plugin being used,", - "This information helps us figure out how to better improve the plugin." - }) - public static final Property toggle_metrics = newProperty("root.toggle_metrics", true); - - @Comment("The prefix that appears in front of messages.") - public static final Property prefix = newProperty("root.prefix", "[CrazyAuctions]: "); -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f1e71ad..4158531 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,10 @@ -org.gradle.jvmargs = '-Xmx3G' -org.gradle.caching = true -org.gradle.parallel = true -org.gradle.warning.mode = all - -authors = ["Ryderbelserion, Badbones69"] -website = https://modrinth.com/plugin/crazyauctions -sources = https://github.com/Crazy-Crew/CrazyAuctions -issues = https://github.com/Crazy-Crew/CrazyAuctions/issues +org.gradle.jvmargs = -Xmx3G +org.gradle.daemon = false +org.gradle.parallel = false group = com.badbones69.crazyauctions +authors = ["Ryderbelserion, Badbones69"] description = Auction off items in style. -version = 1.4.1 -apiVersion = 1.20 - -mcVersion = 1.20.4 -isBeta = true \ No newline at end of file +website = https://modrinth.com/plugin/crazyauctions +sources = https://github.com/Crazy-Crew/CrazyAuctions +issues = https://github.com/Crazy-Crew/CrazyAuctions/issues \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d770e6..8c25e37 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,41 +1,66 @@ -[plugins] -run-paper = { id = "xyz.jpenilla.run-paper", version = "2.2.3" } -shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" } - [versions] -kyori = "4.16.0" -bundle = "1.20.4-R0.1-SNAPSHOT" -cluster = "1.0-SNAPSHOT" +# Minecraft +paper = "1.21-R0.1-SNAPSHOT" +minecraft = "1.21" + +# Plugins +itemsadder = "3.6.3-beta-14" +headdatabaseapi = "1.3.1" +placeholderapi = "2.11.6" +decentholograms = "2.8.8" +fancyholograms = "2.2.0" +worldguard = "7.0.10" +oraxen = "1.171.0" +nbtapi = "2.13.0" +vault = "1.7.1" + +# Libraries +triumph-cmd = "2.0.0-ALPHA-10" +tirumph-gui = "3.1.7" +jetbrains = "24.1.0" +kyori = "4.17.0" +vital = "1.5.9" + +# Paper +paperweight="1.7.1" +runPaper = "2.3.0" +hangar = "0.1.2" + +# Other +shadowJar = "8.1.7" + +# Modrinth +minotaur = "2.+" + +[plugins] +paperweight = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight" } +hangar = { id = "io.papermc.hangar-publish-plugin", version.ref = "hangar" } +shadowJar = { id = "io.github.goooler.shadow", version.ref = "shadowJar" } +runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" } +minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" } [libraries] -simple-yaml = { group = "com.github.Carleslc.Simple-YAML", name = "Simple-Yaml", version = "1.8.4" } +# Plugins +decent-holograms = { module = "com.github.decentsoftware-eu:decentholograms", version.ref = "decentholograms" } +fancy-holograms = { module = "de.oliver:FancyHolograms", version.ref = "fancyholograms" } -minimessage-api = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "kyori" } -adventure-api = { group = "net.kyori", name = "adventure-api", version.ref = "kyori" } +headdatabaseapi = { module = "com.arcaniax:HeadDatabase-API", version.ref = "headdatabaseapi" } +placeholderapi = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } -itemsadder-api = { group = "com.github.LoneDev6", name = "api-itemsadder", version = "3.6.1" } -oraxen-api = { group = "io.th0rgal", name = "oraxen", version = "1.171.0" } -placeholder-api = { group = "me.clip", name = "placeholderapi", version = "2.11.5" } -head-database-api = { group = "com.arcaniax", name = "HeadDatabase-API", version = "1.3.1" } +vault = { module = "com.github.MilkBowl:VaultAPI", version.ref = "vault" } -paperweight-userdev = { group = "io.papermc.paperweight.userdev", name = "io.papermc.paperweight.userdev.gradle.plugin", version = "1.5.11" } -publishing-modrinth = { group = "com.modrinth.minotaur", name = "Minotaur", version = "2.8.7" } -publishing-hangar = { group = "io.papermc", name = "hangar-publish-plugin", version = "0.1.2" } +itemsadder = { module = "com.github.LoneDev6:api-itemsadder", version.ref = "itemsadder" } +oraxen = { module = "io.th0rgal:oraxen", version.ref = "oraxen" } -cluster-api = { group = "com.ryderbelserion.cluster", name = "api", version.ref = "cluster" } -cluster-paper = { group = "com.ryderbelserion.cluster", name = "paper", version.ref = "cluster" } +# Libraries +triumph-cmds = { module = "dev.triumphteam:triumph-cmd-bukkit", version.ref = "triumph-cmd" } +triumph-gui = { module = "dev.triumphteam:triumph-gui", version.ref = "tirumph-gui" } -fancy-holograms = { group = "de.oliver", name = "FancyHolograms", version = "2.0.6" } -decent-holograms = { group = "com.github.decentsoftware-eu", name = "decentholograms", version = "2.8.6" } +jetbrains = { module = "org.jetbrains:annotations", version.ref = "jetbrains" } -triumph-cmds = { group = "dev.triumphteam", name = "triumph-cmd-bukkit", version = "2.0.0-ALPHA-9" } -triumph-gui = { group = "dev.triumphteam", name = "triumph-gui", version = "3.1.7" } - -vault = { group = "com.github.MilkBowl", name = "VaultAPI", version = "1.7.1" } -metrics = { group = "org.bstats", name = "bstats-bukkit", version = "3.0.2" } -config-me = { group = "ch.jalu", name = "configme", version = "1.4.1" } +vital-paper = { module = "com.ryderbelserion.vital:paper", version.ref = "vital" } +vital-core = { module = "com.ryderbelserion.vital:core", version.ref = "vital" } [bundles] -adventure = ["minimessage-api", "adventure-api"] holograms = ["fancy-holograms", "decent-holograms"] triumph = ["triumph-cmds", "triumph-gui"] \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92c1ac1..dab2a01 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/paper/build.gradle.kts b/paper/build.gradle.kts index 6564196..89a6648 100644 --- a/paper/build.gradle.kts +++ b/paper/build.gradle.kts @@ -1,38 +1,53 @@ plugins { + alias(libs.plugins.paperweight) + alias(libs.plugins.shadowJar) + alias(libs.plugins.runPaper) + `paper-plugin` - - id("io.papermc.paperweight.userdev") - - alias(libs.plugins.run.paper) - alias(libs.plugins.shadow) } -repositories { - maven("https://repo.oraxen.com/releases/") +base { + archivesName.set(rootProject.name) } dependencies { - paperweight.paperDevBundle(libs.versions.bundle) + paperweight.paperDevBundle(libs.versions.paper) - implementation(libs.metrics) + compileOnly(libs.placeholderapi) - compileOnly(libs.placeholder.api) - - compileOnly(libs.oraxen.api) + compileOnly(libs.oraxen) compileOnly(libs.vault) compileOnly(fileTree("libs").include("*.jar")) } -tasks { - assemble { - dependsOn(reobfJar) +paperweight { + reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION +} - doLast { - copy { - from(reobfJar.get()) - into(rootProject.projectDir.resolve("jars")) +val component: SoftwareComponent = components["java"] + +tasks { + publishing { + repositories { + maven { + url = uri("https://repo.crazycrew.us/releases") + + credentials { + this.username = System.getenv("gradle_username") + this.password = System.getenv("gradle_password") + } + } + } + + publications { + create("maven") { + groupId = rootProject.group.toString() + artifactId = "${rootProject.name.lowercase()}-${project.name.lowercase()}-api" + version = rootProject.version.toString() + + from(component) } } } @@ -53,32 +68,33 @@ tasks { minecraftVersion("1.20.4") } - shadowJar { - listOf( - //"com.ryderbelserion.cluster", - //"dev.triumphteam.cmd", - //"dev.triumphteam.gui", - "org.bstats" - ).forEach { - relocate(it, "libs.$it") + assemble { + dependsOn(reobfJar) + + doLast { + copy { + from(reobfJar.get()) + into(rootProject.projectDir.resolve("jars")) + } } } + shadowJar { + archiveBaseName.set(rootProject.name) + archiveClassifier.set("") + } + processResources { - val properties = hashMapOf( - "name" to rootProject.name, - "version" to project.version, - "group" to rootProject.group, - "description" to rootProject.description, - "apiVersion" to providers.gradleProperty("apiVersion").get(), - "authors" to providers.gradleProperty("authors").get(), - "website" to providers.gradleProperty("website").get() - ) - - inputs.properties(properties) + inputs.properties("name" to rootProject.name) + inputs.properties("version" to project.version) + inputs.properties("group" to project.group) + inputs.properties("description" to project.properties["description"]) + inputs.properties("apiVersion" to libs.versions.minecraft.get()) + inputs.properties("authors" to project.properties["authors"]) + inputs.properties("website" to project.properties["website"]) filesMatching("plugin.yml") { - expand(properties) + expand(inputs.properties) } } } \ No newline at end of file diff --git a/paper/src/main/java/com/badbones69/crazyauctions/CrazyAuctions.java b/paper/src/main/java/com/badbones69/crazyauctions/CrazyAuctions.java index e08cdd9..be5e4c8 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/CrazyAuctions.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/CrazyAuctions.java @@ -4,7 +4,7 @@ import com.badbones69.crazyauctions.api.CrazyManager; import com.badbones69.crazyauctions.api.FileManager; import com.badbones69.crazyauctions.api.enums.Messages; import com.badbones69.crazyauctions.api.support.PluginSupport; -import com.badbones69.crazyauctions.api.support.metrics.MetricsWrapper; +import com.badbones69.crazyauctions.api.support.MetricsWrapper; import com.badbones69.crazyauctions.commands.AuctionCommand; import com.badbones69.crazyauctions.commands.AuctionTab; import com.badbones69.crazyauctions.controllers.GuiListener; @@ -103,11 +103,10 @@ public class CrazyAuctions extends JavaPlugin { // Enable vault support if enabled. this.support = new VaultSupport(); - support.loadVault(); + this.support.loadVault(); // Create bstats instance. - this.metrics = new MetricsWrapper(); - this.metrics.start(); + this.metrics = new MetricsWrapper(this, 4624); } private void registerCommand(PluginCommand pluginCommand, TabCompleter tabCompleter, CommandExecutor commandExecutor) { diff --git a/paper/src/main/java/com/badbones69/crazyauctions/Methods.java b/paper/src/main/java/com/badbones69/crazyauctions/Methods.java index d34ace7..48daaa7 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/Methods.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/Methods.java @@ -9,6 +9,8 @@ import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -72,13 +74,21 @@ public class Methods { public static Player getPlayer(String name) { try { - return Bukkit.getServer().getPlayer(UUID.fromString(name)); + return Bukkit.getServer().getPlayer(name); } catch (Exception e) { return null; } } - public static OfflinePlayer getOfflinePlayer(String name) { //todo () move off the thread. + public static String toBase64(final ItemStack itemStack) { + return Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()); + } + + public static @NotNull ItemStack fromBase64(final String base64) { + return ItemStack.deserializeBytes(Base64.getDecoder().decode(base64)); + } + + public static OfflinePlayer getOfflinePlayer(String name) { return Bukkit.getServer().getOfflinePlayer(name); } @@ -100,7 +110,6 @@ public class Methods { } p.sendMessage(Messages.NOT_ONLINE.getMessage()); - return false; } @@ -115,7 +124,12 @@ public class Methods { public static boolean hasPermission(CommandSender sender, String perm) { if (sender instanceof Player player) { - return hasPermission(player, perm); + if (!player.hasPermission("crazyauctions." + perm)) { + player.sendMessage(Messages.NO_PERMISSION.getMessage()); + return false; + } + + return true; } return true; @@ -131,7 +145,7 @@ public class Methods { if (index < list.size()) items.add(list.get(index)); } - for (; items.isEmpty(); page--) { + for (; items.size() == 0; page--) { if (page <= 0) break; index = page * max - max; endIndex = index >= list.size() ? list.size() - 1 : index + max; @@ -154,7 +168,7 @@ public class Methods { if (index < list.size()) items.add(list.get(index)); } - for (; items.isEmpty(); page--) { + for (; items.size() == 0; page--) { if (page <= 0) break; index = page * max - max; endIndex = index >= list.size() ? list.size() - 1 : index + max; @@ -256,7 +270,7 @@ public class Methods { if (isOnline(winner) && getPlayer(winner) != null) { Player player = getPlayer(winner); - Bukkit.getPluginManager().callEvent(new AuctionWinBidEvent(player, data.getItemStack("Items." + i + ".Item"), price)); + Bukkit.getPluginManager().callEvent(new AuctionWinBidEvent(player, Methods.fromBase64(data.getString("Items." + i + ".Item")), price)); player.sendMessage(Messages.WIN_BIDDING.getMessage(placeholders)); } @@ -268,7 +282,7 @@ public class Methods { data.set("OutOfTime/Cancelled." + num + ".Seller", winner); data.set("OutOfTime/Cancelled." + num + ".Full-Time", fullExpireTime.getTimeInMillis()); data.set("OutOfTime/Cancelled." + num + ".StoreID", data.getInt("Items." + i + ".StoreID")); - data.set("OutOfTime/Cancelled." + num + ".Item", data.getItemStack("Items." + i + ".Item")); + data.set("OutOfTime/Cancelled." + num + ".Item", data.getString("Items." + i + ".Item")); } else { String seller = data.getString("Items." + i + ".Seller"); Player player = getPlayer(seller); @@ -277,12 +291,12 @@ public class Methods { player.sendMessage(Messages.ITEM_HAS_EXPIRED.getMessage()); } - AuctionExpireEvent event = new AuctionExpireEvent(player, data.getItemStack("Items." + i + ".Item")); + AuctionExpireEvent event = new AuctionExpireEvent(player, Methods.fromBase64(data.getString("Items." + i + ".Item"))); Bukkit.getPluginManager().callEvent(event); data.set("OutOfTime/Cancelled." + num + ".Seller", data.getString("Items." + i + ".Seller")); data.set("OutOfTime/Cancelled." + num + ".Full-Time", fullExpireTime.getTimeInMillis()); data.set("OutOfTime/Cancelled." + num + ".StoreID", data.getInt("Items." + i + ".StoreID")); - data.set("OutOfTime/Cancelled." + num + ".Item", data.getItemStack("Items." + i + ".Item")); + data.set("OutOfTime/Cancelled." + num + ".Item", data.getString("Items." + i + ".Item")); } data.set("Items." + i, null); diff --git a/paper/src/main/java/com/badbones69/crazyauctions/api/CrazyManager.java b/paper/src/main/java/com/badbones69/crazyauctions/api/CrazyManager.java index 2bfa6c7..a7ab4e7 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/api/CrazyManager.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/api/CrazyManager.java @@ -1,5 +1,6 @@ package com.badbones69.crazyauctions.api; +import com.badbones69.crazyauctions.Methods; import com.badbones69.crazyauctions.api.FileManager.Files; import com.badbones69.crazyauctions.api.enums.ShopType; import org.bukkit.configuration.file.FileConfiguration; @@ -39,11 +40,11 @@ public class CrazyManager { if (data.getString("Items." + i + ".Seller").equalsIgnoreCase(player.getUniqueId().toString())) { if (data.getBoolean("Items." + i + ".Biddable")) { if (type == ShopType.BID) { - items.add(data.getItemStack("Items." + i + ".Item").clone()); + items.add(Methods.fromBase64(data.getString("Items." + i + ".Item"))); } } else { if (type == ShopType.SELL) { - items.add(data.getItemStack("Items." + i + ".Item").clone()); + items.add(Methods.fromBase64(data.getString("Items." + i + ".Item"))); } } } diff --git a/paper/src/main/java/com/badbones69/crazyauctions/api/CustomMetrics.java b/paper/src/main/java/com/badbones69/crazyauctions/api/CustomMetrics.java new file mode 100644 index 0000000..c2274af --- /dev/null +++ b/paper/src/main/java/com/badbones69/crazyauctions/api/CustomMetrics.java @@ -0,0 +1,955 @@ +package com.badbones69.crazyauctions.api; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.net.ssl.HttpsURLConnection; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class CustomMetrics { + + private final JavaPlugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public CustomMetrics(JavaPlugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config + .options() + .setHeader( + List.of( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how", + "many people use their plugin and their total player count. It's recommended to keep bStats", + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no", + "performance penalty associated with having metrics enabled, and data sent to bStats is fully", + "anonymous." + )) + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) {} + } + + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + + this.metricsBase = new MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + submitDataTask -> plugin.getServer().getGlobalRegionScheduler().execute(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> plugin.getLogger().log(Level.WARNING, message, error), + (message) -> plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText); + } + + /** + * Shuts down the underlying scheduler service. + */ + public void shutdown() { + this.metricsBase.shutdown(); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + this.metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", this.plugin.getPluginMeta().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** + * The version of the Metrics class. + */ + public static final String METRICS_VERSION = "3.0.2"; + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final ScheduledExecutorService scheduler; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether errors should be logged. + * @param logSentData Whether the scent data should be logged. + * @param logResponseStatusText Whether the response status text should be logged. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText) { + ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1, task -> new Thread(task, "bStats-Metrics")); + + // We want delayed tasks (non-periodic) that will execute in the future to be + // cancelled when the scheduler is shutdown. + // Otherwise, we risk preventing the server from shutting down even when + // MetricsBase#shutdown() is called + scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + + this.scheduler = scheduler; + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + + checkRelocation(); + + if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from + // bStats + startSubmitting(); + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + + return outputStream.toByteArray(); + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + public void shutdown() { + this.scheduler.shutdown(); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!this.enabled || !this.checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + this.scheduler.shutdown(); + + return; + } + + if (this.submitTaskConsumer != null) { + this.submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven + // distribution of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into + // the initial and second delay. + // WARNING: You must not modify and part of this Metrics class, including the + // submit delay or frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just + // don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + this.scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + this.scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + this.appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + this.appendServiceDataConsumer.accept(serviceJsonBuilder); + + JsonObjectBuilder.JsonObject[] chartData = + this.customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(this.errorLogger, this.logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + + serviceJsonBuilder.appendField("id", this.serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", this.serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + + this.scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (this.logErrors) { + this.errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (this.logSentData) { + this.infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + + String url = String.format(REPORT_URL, this.platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + + StringBuilder builder = new StringBuilder(); + + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + + if (this.logResponseStatusText) { + this.infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** + * Checks that the class was properly relocated. + */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this + // little "trick" ... :D + final String defaultPackage = new String(new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong package names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = this.callable.call(); + + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + + Map map = this.callable.call(); + + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + + boolean allSkipped = true; + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + + if (allSkipped) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + + Map map = this.callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + + boolean allSkipped = true; + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + + if (allSkipped) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + + Map map = this.callable.call(); + + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[]{entry.getValue()}); + } + + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + + Map map = this.callable.call(); + + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + + boolean allSkipped = true; + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + + allSkipped = false; + + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + + if (allSkipped) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + + Map> map = this.callable.call(); + + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + + boolean reallyAllSkipped = true; + + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + + boolean allSkipped = true; + + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject(BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + + builder.appendField("chartId", this.chartId); + + try { + JsonObjectBuilder.JsonObject data = getChartData(); + + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + + return null; + } + + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = this.callable.call(); + + if (value == 0) { + // Null = skip the chart + return null; + } + + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + this.builder.append("{"); + } + + /** + * Escapes the given string like stated in .... + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + + return builder.toString(); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + + appendFieldUnescaped(key, object.toString()); + + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + + String escapedValues = Arrays.stream(values).map(value -> "\"" + escape(value) + "\"").collect(Collectors.joining(",")); + + appendFieldUnescaped(key, "[" + escapedValues + "]"); + + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + + String escapedValues = Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + + appendFieldUnescaped(key, "[" + escapedValues + "]"); + + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + + String escapedValues = Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + + appendFieldUnescaped(key, "[" + escapedValues + "]"); + + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (this.builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + + if (this.hasAtLeastOneField) { + this.builder.append(","); + } + + this.builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + + this.hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (this.builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + + JsonObject object = new JsonObject(this.builder.append("}").toString()); + + this.builder = null; + + return object; + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + } +} \ No newline at end of file diff --git a/paper/src/main/java/com/badbones69/crazyauctions/api/builders/ItemBuilder.java b/paper/src/main/java/com/badbones69/crazyauctions/api/builders/ItemBuilder.java index 20ab42d..9414bd6 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/api/builders/ItemBuilder.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/api/builders/ItemBuilder.java @@ -4,15 +4,12 @@ import com.badbones69.crazyauctions.CrazyAuctions; import com.badbones69.crazyauctions.Methods; import com.badbones69.crazyauctions.api.support.PluginSupport; import com.badbones69.crazyauctions.api.support.SkullCreator; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import io.th0rgal.oraxen.api.OraxenItems; import me.clip.placeholderapi.PlaceholderAPI; -import net.minecraft.nbt.TagParser; import org.bukkit.*; import org.bukkit.block.Banner; import org.bukkit.block.banner.Pattern; import org.bukkit.block.banner.PatternType; -import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -315,19 +312,6 @@ public class ItemBuilder { } if (this.itemStack.getType() != Material.AIR) { - // If item data is not empty. We ignore all other options and simply return. - if (!this.itemData.isEmpty()) { - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(getItemStack()); - - try { - nmsItem.setTag(TagParser.parseTag(this.itemData)); - } catch (CommandSyntaxException exception) { - this.plugin.getLogger().log(Level.WARNING, "Failed to set nms tag.", exception); - } - - return CraftItemStack.asBukkitCopy(nmsItem); - } - getItemStack().setAmount(this.itemAmount); getItemStack().editMeta(itemMeta -> { @@ -411,17 +395,14 @@ public class ItemBuilder { itemMeta.setUnbreakable(this.isUnbreakable); if (this.isGlowing) { - if (!itemMeta.hasEnchants()) { - itemMeta.addEnchant(Enchantment.LUCK, 1, false); - itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - } + itemMeta.setEnchantmentGlintOverride(true); } itemMeta.setDisplayName(getUpdatedName()); itemMeta.setLore(getUpdatedLore()); }); } else { - Logger logger = this.plugin.getLogger(); + Logger logger = plugin.getLogger(); logger.warning("Material cannot be of type AIR or null, If you see this."); logger.warning("in your console but do not have any invalid items. You can"); @@ -1103,6 +1084,12 @@ public class ItemBuilder { return new ItemBuilder(item).setAmount(item.getAmount()).setEnchantments(new HashMap<>(item.getEnchantments())); } + public static ItemBuilder convertItemStack(String item) { + ItemStack itemStack = Methods.fromBase64(item); + + return new ItemBuilder(itemStack).setAmount(itemStack.getAmount()).setEnchantments(new HashMap<>(itemStack.getEnchantments())); + } + public static ItemBuilder convertItemStack(ItemStack item, Player player) { return new ItemBuilder(item).setTarget(player).setAmount(item.getAmount()).setEnchantments(new HashMap<>(item.getEnchantments())); } @@ -1232,27 +1219,27 @@ public class ItemBuilder { if (type != null) { if (type.equals(PotionEffectType.FIRE_RESISTANCE)) { return PotionType.FIRE_RESISTANCE; - } else if (type.equals(PotionEffectType.HARM)) { - return PotionType.INSTANT_DAMAGE; - } else if (type.equals(PotionEffectType.HEAL)) { - return PotionType.INSTANT_HEAL; + } else if (type.equals(PotionEffectType.INSTANT_DAMAGE)) { + return PotionType.STRONG_HARMING; + } else if (type.equals(PotionEffectType.INSTANT_HEALTH)) { + return PotionType.HEALING; } else if (type.equals(PotionEffectType.INVISIBILITY)) { return PotionType.INVISIBILITY; - } else if (type.equals(PotionEffectType.JUMP)) { - return PotionType.JUMP; - } else if (type.equals(PotionEffectType.getByName("LUCK"))) { - return PotionType.valueOf("LUCK"); + } else if (type.equals(PotionEffectType.JUMP_BOOST)) { + return PotionType.LEAPING; + } else if (type.equals(PotionEffectType.LUCK)) { + return PotionType.LUCK; } else if (type.equals(PotionEffectType.NIGHT_VISION)) { return PotionType.NIGHT_VISION; } else if (type.equals(PotionEffectType.POISON)) { return PotionType.POISON; } else if (type.equals(PotionEffectType.REGENERATION)) { - return PotionType.REGEN; - } else if (type.equals(PotionEffectType.SLOW)) { + return PotionType.REGENERATION; + } else if (type.equals(PotionEffectType.SLOWNESS)) { return PotionType.SLOWNESS; } else if (type.equals(PotionEffectType.SPEED)) { - return PotionType.SPEED; - } else if (type.equals(PotionEffectType.INCREASE_DAMAGE)) { + return PotionType.SWIFTNESS; + } else if (type.equals(PotionEffectType.STRENGTH)) { return PotionType.STRENGTH; } else if (type.equals(PotionEffectType.WATER_BREATHING)) { return PotionType.WATER_BREATHING; diff --git a/paper/src/main/java/com/badbones69/crazyauctions/api/support/MetricsWrapper.java b/paper/src/main/java/com/badbones69/crazyauctions/api/support/MetricsWrapper.java new file mode 100644 index 0000000..701fe8b --- /dev/null +++ b/paper/src/main/java/com/badbones69/crazyauctions/api/support/MetricsWrapper.java @@ -0,0 +1,16 @@ +package com.badbones69.crazyauctions.api.support; + +import com.badbones69.crazyauctions.CrazyAuctions; +import com.badbones69.crazyauctions.api.CustomMetrics; + +public class MetricsWrapper extends CustomMetrics { + + /** + * Creates a new Metrics instance. + * + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public MetricsWrapper(CrazyAuctions plugin, int serviceId) { + super(plugin, serviceId); + } +} \ No newline at end of file diff --git a/paper/src/main/java/com/badbones69/crazyauctions/api/support/metrics/MetricsWrapper.java b/paper/src/main/java/com/badbones69/crazyauctions/api/support/metrics/MetricsWrapper.java deleted file mode 100644 index b60e969..0000000 --- a/paper/src/main/java/com/badbones69/crazyauctions/api/support/metrics/MetricsWrapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.badbones69.crazyauctions.api.support.metrics; - -import com.badbones69.crazyauctions.CrazyAuctions; -import org.bstats.bukkit.Metrics; -import org.jetbrains.annotations.NotNull; - -public class MetricsWrapper { - - @NotNull - private final CrazyAuctions plugin = CrazyAuctions.get(); - - private Metrics metrics; - - public void start() { - if (this.metrics != null) { - if (this.plugin.isLogging()) this.plugin.getLogger().warning("Metrics is already enabled."); - return; - } - - this.metrics = new Metrics(this.plugin, 4624); - - if (this.plugin.isLogging()) this.plugin.getLogger().fine("Metrics has been enabled."); - } - - public void stop() { - if (this.metrics == null) { - if (this.plugin.isLogging()) this.plugin.getLogger().warning("Metrics isn't enabled so we do nothing."); - return; - } - - this.metrics.shutdown(); - this.metrics = null; - - if (this.plugin.isLogging()) this.plugin.getLogger().fine("Metrics has been turned off."); - } -} \ No newline at end of file diff --git a/paper/src/main/java/com/badbones69/crazyauctions/commands/AuctionCommand.java b/paper/src/main/java/com/badbones69/crazyauctions/commands/AuctionCommand.java index ad38bfb..0f1ff5f 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/commands/AuctionCommand.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/commands/AuctionCommand.java @@ -133,7 +133,7 @@ public class AuctionCommand implements CommandExecutor { ItemStack stack = item.clone(); stack.setAmount(amount); - data.set("Items." + num + ".Item", Base64.getEncoder().encodeToString(stack.serializeAsBytes())); + data.set("Items." + num + ".Item", Methods.toBase64(stack)); } Files.DATA.saveFile(); @@ -408,7 +408,7 @@ public class AuctionCommand implements CommandExecutor { ItemStack stack = item.clone(); stack.setAmount(amount); - data.set("Items." + num + ".Item", Base64.getEncoder().encodeToString(stack.serializeAsBytes())); + data.set("Items." + num + ".Item", Methods.toBase64(stack)); Files.DATA.saveFile(); diff --git a/paper/src/main/java/com/badbones69/crazyauctions/controllers/GuiListener.java b/paper/src/main/java/com/badbones69/crazyauctions/controllers/GuiListener.java index abb8abe..6912a3d 100644 --- a/paper/src/main/java/com/badbones69/crazyauctions/controllers/GuiListener.java +++ b/paper/src/main/java/com/badbones69/crazyauctions/controllers/GuiListener.java @@ -6,7 +6,7 @@ import com.badbones69.crazyauctions.api.*; import com.badbones69.crazyauctions.api.FileManager.Files; import com.badbones69.crazyauctions.api.builders.ItemBuilder; import com.badbones69.crazyauctions.api.enums.Category; -import com.badbones69.crazyauctions.api.enums.Reasons; +import com.badbones69.crazyauctions.api.enums.Reaons; import com.badbones69.crazyauctions.api.enums.Messages; import com.badbones69.crazyauctions.api.enums.ShopType; import com.badbones69.crazyauctions.api.events.AuctionBuyEvent; @@ -67,7 +67,7 @@ public class GuiListener implements Listener { for (String i : data.getConfigurationSection("Items").getKeys(false)) { List lore = new ArrayList<>(); - ItemBuilder itemBuilder = ItemBuilder.convertItemStack(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + i + ".Item")))); + ItemBuilder itemBuilder = ItemBuilder.convertItemStack(data.getString("Items." + i + ".Item")); if (itemBuilder != null && data.contains("Items." + i + ".Item") && (cat.getItems().contains(itemBuilder.getItemStack().getType()) || cat == Category.NONE)) { if (data.getBoolean("Items." + i + ".Biddable")) { @@ -75,12 +75,7 @@ public class GuiListener implements Listener { String seller = data.getString("Items." + i + ".Seller"); String topbidder = data.getString("Items." + i + ".TopBidder"); for (String l : config.getStringList("Settings.GUISettings.Bidding")) { - lore.add(l.replace("%TopBid%", Methods.getPrice(i, false)) - .replace("%topbid%", Methods.getPrice(i, false)) - .replace("%Seller%", seller).replace("%seller%", seller) - .replace("%TopBidder%", topbidder).replace("%topbidder%", topbidder) - .replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))) - .replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); + lore.add(l.replace("%TopBid%", Methods.getPrice(i, false)).replace("%topbid%", Methods.getPrice(i, false)).replace("%Seller%", seller).replace("%seller%", seller).replace("%TopBidder%", topbidder).replace("%topbidder%", topbidder).replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); } itemBuilder.setLore(lore); @@ -92,11 +87,7 @@ public class GuiListener implements Listener { } else { if (sell == ShopType.SELL) { for (String l : config.getStringList("Settings.GUISettings.SellingItemLore")) { - lore.add(l.replace("%Price%", String.format(Locale.ENGLISH, "%,d", Long.parseLong(Methods.getPrice(i, false)))) - .replace("%price%", String.format(Locale.ENGLISH, "%,d", Long.parseLong(Methods.getPrice(i, false)))) - .replace("%Seller%", data.getString("Items." + i + ".Seller")).replace("%seller%", data.getString("Items." + i + ".Seller")) - .replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))) - .replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); + lore.add(l.replace("%Price%", String.format(Locale.ENGLISH, "%,d", Long.parseLong(Methods.getPrice(i, false)))).replace("%price%", String.format(Locale.ENGLISH, "%,d", Long.parseLong(Methods.getPrice(i, false)))).replace("%Seller%", data.getString("Items." + i + ".Seller")).replace("%seller%", data.getString("Items." + i + ".Seller")).replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); } itemBuilder.setLore(lore); @@ -257,16 +248,13 @@ public class GuiListener implements Listener { if (data.contains("Items")) { for (String i : data.getConfigurationSection("Items").getKeys(false)) { - if (data.getString("Items." + i + ".Seller").equalsIgnoreCase(player.getUniqueId().toString())) { + if (data.getString("Items." + i + ".Seller").equalsIgnoreCase(player.getName())) { List lore = new ArrayList<>(); for (String l : config.getStringList("Settings.GUISettings.CurrentLore")) { - lore.add(l.replace("%Price%", Methods.getPrice(i, false)) - .replace("%price%", Methods.getPrice(i, false)) - .replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))) - .replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); + lore.add(l.replace("%Price%", Methods.getPrice(i, false)).replace("%price%", Methods.getPrice(i, false)).replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); } - ItemBuilder itemBuilder = ItemBuilder.convertItemStack(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + i + ".Item")))); + ItemBuilder itemBuilder = ItemBuilder.convertItemStack(data.getString("Items." + i + ".Item")); itemBuilder.setLore(lore); @@ -297,16 +285,13 @@ public class GuiListener implements Listener { if (data.contains("OutOfTime/Cancelled")) { for (String i : data.getConfigurationSection("OutOfTime/Cancelled").getKeys(false)) { if (data.getString("OutOfTime/Cancelled." + i + ".Seller") != null) { - if (data.getString("OutOfTime/Cancelled." + i + ".Seller").equalsIgnoreCase(player.getUniqueId().toString())) { + if (data.getString("OutOfTime/Cancelled." + i + ".Seller").equalsIgnoreCase(player.getName())) { List lore = new ArrayList<>(); for (String l : config.getStringList("Settings.GUISettings.Cancelled/ExpiredLore")) { - lore.add(l.replace("%Price%", Methods.getPrice(i, true)) - .replace("%price%", Methods.getPrice(i, true)) - .replace("%Time%", Methods.convertToTime(data.getLong("OutOfTime/Cancelled." + i + ".Full-Time"))) - .replace("%time%", Methods.convertToTime(data.getLong("OutOfTime/Cancelled." + i + ".Full-Time")))); + lore.add(l.replace("%Price%", Methods.getPrice(i, true)).replace("%price%", Methods.getPrice(i, true)).replace("%Time%", Methods.convertToTime(data.getLong("OutOfTime/Cancelled." + i + ".Full-Time"))).replace("%time%", Methods.convertToTime(data.getLong("OutOfTime/Cancelled." + i + ".Full-Time")))); } - ItemBuilder itemBuilder = ItemBuilder.convertItemStack(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("OutOfTime/Cancelled." + i + ".Item")))); + ItemBuilder itemBuilder = ItemBuilder.convertItemStack(data.getString("OutOfTime/Cancelled." + i + ".Item")); itemBuilder.setLore(lore); @@ -406,30 +391,12 @@ public class GuiListener implements Listener { } } - ItemStack item = ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item"))); List lore = new ArrayList<>(); - - final String price = Methods.getPrice(ID, false); - - for (String key : config.getStringList("Settings.GUISettings.SellingItemLore")) { - String line = key.replace("%Price%", price).replace("%price%", price); - - String uuid = data.getString("Items." + ID + ".Seller"); - - if (uuid != null) { - Player person = plugin.getServer().getPlayer(UUID.fromString(uuid)); - - if (person != null) { - line = line.replace("%Seller%", person.getName()).replace("%seller%", person.getName()); - } - } - - final String time = Methods.convertToTime(data.getLong("Items." + key + ".Time-Till-Expire")); - - lore.add(line.replace("%Time%", time).replace("%time%", time)); + for (String l : config.getStringList("Settings.GUISettings.SellingItemLore")) { + lore.add(l.replace("%Price%", Methods.getPrice(ID, false)).replace("%price%", Methods.getPrice(ID, false)).replace("%Seller%", data.getString("Items." + ID + ".Seller")).replace("%seller%", data.getString("Items." + ID + ".Seller")).replace("%Time%", Methods.convertToTime(data.getLong("Items." + l + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + l + ".Time-Till-Expire")))); } - ItemBuilder itemBuilder = ItemBuilder.convertItemStack(item); + ItemBuilder itemBuilder = ItemBuilder.convertItemStack(data.getString("Items." + ID + ".Item")); itemBuilder.setLore(lore); @@ -447,7 +414,6 @@ public class GuiListener implements Listener { if (!data.contains("Items." + ID)) { openShop(player, ShopType.BID, shopCategory.get(player.getUniqueId()), 1); player.sendMessage(Messages.ITEM_DOESNT_EXIST.getMessage()); - return; } @@ -482,76 +448,32 @@ public class GuiListener implements Listener { if (!data.contains("Items")) { data.set("Items.Clear", null); - Files.DATA.saveFile(); } - Player otherPlayer = plugin.getServer().getPlayer(UUID.fromString(other)); - if (data.contains("Items")) { for (String i : data.getConfigurationSection("Items").getKeys(false)) { - - final String tag = data.getString("Items." + i + ".Seller"); - - if (tag != null) { + if (data.getString("Items." + i + ".Seller").equalsIgnoreCase(other)) { List lore = new ArrayList<>(); - - if (otherPlayer != null && tag.equalsIgnoreCase(otherPlayer.getUniqueId().toString())) { - final String time = Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")); - - final String price = Methods.getPrice(i, false); - - if (data.getBoolean("Items." + i + ".Biddable")) { - String uuid = data.getString("Items." + i + ".Seller"); - String topbidder = data.getString("Items." + i + ".TopBidder"); - - for (String key : config.getStringList("Settings.GUISettings.Bidding")) { - String line = key.replace("%Price%", price).replace("%price%", price); - - if (uuid != null) { - Player person = plugin.getServer().getPlayer(UUID.fromString(uuid)); - - if (person != null) { - line = line.replace("%Seller%", person.getName()).replace("%seller%", person.getName()); - } - } - - if (topbidder != null) { - Player person = plugin.getServer().getPlayer(UUID.fromString(topbidder)); - - if (person != null) { - line = line.replace("%TopBidder%", person.getName()).replace("%topbidder%", person.getName()); - } - } - - lore.add(line.replace("%Time%", time).replace("%time%", time).replace("%TopBid%", price).replace("%topbid%", price)); - } - } else { - for (String key : config.getStringList("Settings.GUISettings.SellingItemLore")) { - String line = key.replace("%Price%", price).replace("%price%", price); - - String uuid = data.getString("Items." + i + ".Seller"); - - if (uuid != null) { - Player person = plugin.getServer().getPlayer(UUID.fromString(uuid)); - - if (person != null) { - line = line.replace("%Seller%", person.getName()).replace("%seller%", person.getName()); - } - } - - lore.add(line.replace("%Price%", price).replace("%price%", price).replace("%Time%", time).replace("%time%", time)); - } + if (data.getBoolean("Items." + i + ".Biddable")) { + String seller = data.getString("Items." + i + ".Seller"); + String topbidder = data.getString("Items." + i + ".TopBidder"); + for (String l : config.getStringList("Settings.GUISettings.Bidding")) { + lore.add(l.replace("%TopBid%", Methods.getPrice(i, false)).replace("%topbid%", Methods.getPrice(i, false)).replace("%Seller%", seller).replace("%seller%", seller).replace("%TopBidder%", topbidder).replace("%topbidder%", topbidder).replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); + } + } else { + for (String l : config.getStringList("Settings.GUISettings.SellingItemLore")) { + lore.add(l.replace("%Price%", Methods.getPrice(i, false)).replace("%price%", Methods.getPrice(i, false)).replace("%Seller%", data.getString("Items." + i + ".Seller")).replace("%seller%", data.getString("Items." + i + ".Seller")).replace("%Time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + i + ".Time-Till-Expire")))); } - - ItemBuilder itemBuilder = ItemBuilder.convertItemStack(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item")))); - - itemBuilder.setLore(lore); - - items.add(itemBuilder.build()); - - ID.add(data.getInt("Items." + i + ".StoreID")); } + + ItemBuilder itemBuilder = ItemBuilder.convertItemStack(data.getString("Items." + ID + ".Item")); + + itemBuilder.setLore(lore); + + items.add(itemBuilder.build()); + + ID.add(data.getInt("Items." + i + ".StoreID")); } } } @@ -605,11 +527,8 @@ public class GuiListener implements Listener { if (config.contains("Settings.GUISettings.OtherSettings.Bidding.Lore")) { List lore = new ArrayList<>(); - - final String price = Methods.getPrice(ID, false); - - for (String line : config.getStringList("Settings.GUISettings.OtherSettings.Bidding.Lore")) { - lore.add(line.replace("%Bid%", String.valueOf(bid)).replace("%bid%", String.valueOf(bid)).replace("%TopBid%", price).replace("%topbid%", price)); + for (String l : config.getStringList("Settings.GUISettings.OtherSettings.Bidding.Lore")) { + lore.add(l.replace("%Bid%", bid + "").replace("%bid%", bid + "").replace("%TopBid%", Methods.getPrice(ID, false)).replace("%topbid%", Methods.getPrice(ID, false))); } itemBuilder.setLore(lore); @@ -621,42 +540,13 @@ public class GuiListener implements Listener { private static ItemStack getBiddingItem(String ID) { FileConfiguration config = Files.CONFIG.getFile(); FileConfiguration data = Files.DATA.getFile(); - String seller = data.getString("Items." + ID + ".Seller"); - - Player player = null; - - if (seller != null) { - player = plugin.getServer().getPlayer(UUID.fromString(seller)); - } - String topbidder = data.getString("Items." + ID + ".TopBidder"); - - Player bidder = null; - - if (topbidder != null) { - bidder = plugin.getServer().getPlayer(UUID.fromString(topbidder)); - } - - ItemStack item = ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item"))); + ItemStack item = Methods.fromBase64(data.getString("Items." + ID + ".Item")); List lore = new ArrayList<>(); - final String price = Methods.getPrice(ID, false); - - final String time = Methods.convertToTime(data.getLong("Items." + ID + ".Time-Till-Expire")); - - for (String key : config.getStringList("Settings.GUISettings.Bidding")) { - String line = key.replace("%TopBid%", time).replace("%topbid%", time); - - if (player != null) { - line = line.replace("%Seller%", player.getName()).replace("%seller%", player.getName()); - } - - if (bidder != null) { - line = line.replace("%TopBidder%", bidder.getName()).replace("%topbidder%", bidder.getName()); - } - - lore.add(line.replace("%TopBid%", price).replace("%topbid%", price).replace("%time%", time).replace("%Time%", time)); + for (String l : config.getStringList("Settings.GUISettings.Bidding")) { + lore.add(l.replace("%TopBid%", Methods.getPrice(ID, false)).replace("%topbid%", Methods.getPrice(ID, false)).replace("%Seller%", seller).replace("%seller%", seller).replace("%TopBidder%", topbidder).replace("%topbidder%", topbidder).replace("%Time%", Methods.convertToTime(data.getLong("Items." + ID + ".Time-Till-Expire"))).replace("%time%", Methods.convertToTime(data.getLong("Items." + ID + ".Time-Till-Expire")))); } ItemBuilder itemBuilder = ItemBuilder.convertItemStack(item); @@ -682,9 +572,7 @@ public class GuiListener implements Listener { private void playSoldSound(@NotNull Player player) { FileConfiguration config = Files.CONFIG.getFile(); - - String sound = config.getString("Settings.Sold-Item-Sound", "UI_BUTTON_CLICK"); - + String sound = config.getString("Settings.Sold-Item-Sound", ""); if (sound.isEmpty()) return; try { @@ -770,9 +658,10 @@ public class GuiListener implements Listener { return; } - Bukkit.getPluginManager().callEvent(new AuctionNewBidEvent(player, ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item"))), bid)); + + Bukkit.getPluginManager().callEvent(new AuctionNewBidEvent(player, Methods.fromBase64(data.getString("Items." + ID + ".Item")), bid)); data.set("Items." + ID + ".Price", bid); - data.set("Items." + ID + ".TopBidder", player.getUniqueId().toString()); + data.set("Items." + ID + ".TopBidder", player.getName()); HashMap placeholders = new HashMap<>(); placeholders.put("%Bid%", bid + ""); player.sendMessage(Messages.BID_MESSAGE.getMessage(placeholders)); @@ -919,9 +808,8 @@ public class GuiListener implements Listener { sellerPlayer.sendMessage(Messages.ADMIN_FORCE_CANCELLED_TO_PLAYER.getMessage()); } - AuctionCancelledEvent event = new AuctionCancelledEvent((sellerPlayer != null ? sellerPlayer : Methods.getOfflinePlayer(seller)), ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item"))), Reasons.ADMIN_FORCE_CANCEL); - plugin.getServer().getPluginManager().callEvent(event); - + AuctionCancelledEvent event = new AuctionCancelledEvent((sellerPlayer != null ? sellerPlayer : Bukkit.getOfflinePlayer(seller)), Methods.fromBase64(data.getString("Items." + ID + ".Item")), Reaons.ADMIN_FORCE_CANCEL); + Bukkit.getPluginManager().callEvent(event); data.set("OutOfTime/Cancelled." + num + ".Seller", data.getString("Items." + i + ".Seller")); data.set("OutOfTime/Cancelled." + num + ".Full-Time", data.getLong("Items." + i + ".Full-Time")); data.set("OutOfTime/Cancelled." + num + ".StoreID", data.getInt("Items." + i + ".StoreID")); @@ -969,12 +857,11 @@ public class GuiListener implements Listener { inv.setItem(slot, itemBuilder.build()); playClick(player); Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable, 3 * 20); - return; } if (data.getBoolean("Items." + i + ".Biddable")) { - if (player.getUniqueId().toString().equalsIgnoreCase(data.getString("Items." + i + ".TopBidder"))) { + if (player.getName().equalsIgnoreCase(data.getString("Items." + i + ".TopBidder"))) { String itemName = config.getString("Settings.GUISettings.OtherSettings.Top-Bidder.Item"); String name = config.getString("Settings.GUISettings.OtherSettings.Top-Bidder.Name"); @@ -987,7 +874,6 @@ public class GuiListener implements Listener { inv.setItem(slot, itemBuilder.build()); playClick(player); Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable, 3 * 20); - return; } @@ -1008,7 +894,6 @@ public class GuiListener implements Listener { playClick(player); openShop(player, shopType.get(player.getUniqueId()), shopCategory.get(player.getUniqueId()), 1); player.sendMessage(Messages.ITEM_DOESNT_EXIST.getMessage()); - return; } } @@ -1057,12 +942,11 @@ public class GuiListener implements Listener { return; } - ItemStack i = ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + ID + ".Item"))); + ItemStack i = Methods.fromBase64(data.getString("Items." + ID + ".Item")); plugin.getServer().getPluginManager().callEvent(new AuctionBuyEvent(player, i, cost)); plugin.getSupport().removeMoney(player, cost); plugin.getSupport().addMoney(Methods.getOfflinePlayer(seller), cost); - HashMap placeholders = new HashMap<>(); placeholders.put("%Price%", Methods.getPrice(ID, false)); placeholders.put("%price%", Methods.getPrice(ID, false)); @@ -1070,7 +954,6 @@ public class GuiListener implements Listener { placeholders.put("%player%", player.getName()); player.sendMessage(Messages.BOUGHT_ITEM.getMessage(placeholders)); - if (Methods.isOnline(seller) && Methods.getPlayer(seller) != null) { Player sell = Methods.getPlayer(seller); sell.sendMessage(Messages.PLAYER_BOUGHT_ITEM.getMessage(placeholders)); @@ -1122,7 +1005,7 @@ public class GuiListener implements Listener { int ID = data.getInt("Items." + i + ".StoreID"); if (id == ID) { player.sendMessage(Messages.CANCELLED_ITEM.getMessage()); - AuctionCancelledEvent event = new AuctionCancelledEvent(player, ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("Items." + i + ".Item"))), Reasons.PLAYER_FORCE_CANCEL); + AuctionCancelledEvent event = new AuctionCancelledEvent(player, Methods.fromBase64(data.getString("Items." + i + ".Item")), Reaons.PLAYER_FORCE_CANCEL); Bukkit.getPluginManager().callEvent(event); int num = 1; for (; data.contains("OutOfTime/Cancelled." + num); num++) ; @@ -1186,7 +1069,7 @@ public class GuiListener implements Listener { player.sendMessage(Messages.INVENTORY_FULL.getMessage()); break; } else { - player.getInventory().addItem(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("OutOfTime/Cancelled." + i + ".Item")))); + player.getInventory().addItem(Methods.fromBase64(data.getString("OutOfTime/Cancelled." + i + ".Item"))); data.set("OutOfTime/Cancelled." + i, null); } } @@ -1219,7 +1102,7 @@ public class GuiListener implements Listener { if (id == ID) { if (!Methods.isInvFull(player)) { player.sendMessage(Messages.GOT_ITEM_BACK.getMessage()); - player.getInventory().addItem(ItemStack.deserializeBytes(Base64.getDecoder().decode(data.getString("OutOfTime/Cancelled." + i + ".Item")))); + player.getInventory().addItem(Methods.fromBase64(data.getString("OutOfTime/Cancelled." + i + ".Item"))); data.set("OutOfTime/Cancelled." + i, null); Files.DATA.saveFile(); playClick(player); @@ -1245,4 +1128,4 @@ public class GuiListener implements Listener { } } } -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 824a9c3..906547b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,14 +1,19 @@ +import com.ryderbelserion.feather.includeProject + enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -pluginManagement { - repositories { - maven("https://repo.papermc.io/repository/maven-public/") - - gradlePluginPortal() - mavenCentral() - } -} - rootProject.name = "CrazyAuctions" -include(":paper") \ No newline at end of file +pluginManagement { + repositories { + maven("https://repo.crazycrew.us/releases") + + gradlePluginPortal() + } +} + +plugins { + id("com.ryderbelserion.feather-settings") version "0.0.1" +} + +listOf("paper").forEach(::includeProject) \ No newline at end of file