diff --git a/build.gradle b/build.gradle index 173c78a..fe34596 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,16 @@ plugins { id 'java' + id 'com.github.johnrengelman.shadow' version '6.1.0' id "io.freefair.lombok" version "5.1.0" } group 'sh.okx' -version '3.11.4-beta' +version '3.12' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} repositories { mavenCentral() @@ -24,27 +30,42 @@ repositories { dependencies { testImplementation group: 'junit', name: 'junit', version: '4.12' - testImplementation 'com.github.seeseemelk:MockBukkit-v1.15:0.3.0' + testImplementation 'com.github.seeseemelk:MockBukkit-v1.16:1.0.0' + testImplementation group: 'org.slf4j', name: 'slf4j-nop', version: '1.7.30' + testImplementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30' compileOnly 'org.jetbrains:annotations:16.0.2' - implementation 'org.spigotmc:spigot-api:1.16.4-R0.1-SNAPSHOT' - implementation('com.github.Realizedd:TokenManager:3.2.4') { + compileOnly 'org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT' + compileOnly('com.github.Realizedd:TokenManager:3.2.4') { transitive = false } - implementation('com.github.MilkBowl:VaultAPI:1.7') { + compileOnly('com.github.MilkBowl:VaultAPI:1.7') { exclude group: 'org.bukkit' } - implementation ('me.clip:placeholderapi:2.10.9') { + compileOnly ('me.clip:placeholderapi:2.10.9') { exclude group: 'org.bstats' } - implementation 'com.github.pyvesb:advanced-achievements:6.7.2' - implementation 'com.github.astei:Superbvote:700fca43659b438cb9bb36c218a7646d2f2ef315' - implementation('com.github.mcMMO-Dev:mcMMO:601297') { + compileOnly 'com.github.pyvesb:advanced-achievements:6.7.2' + compileOnly 'com.github.astei:Superbvote:700fca43659b438cb9bb36c218a7646d2f2ef315' + compileOnly('com.github.mcMMO-Dev:mcMMO:601297') { exclude group: 'com.sk89q.worldguard' } - implementation 'com.github.BenCodez:VotingPlugin:6.0' - implementation 'com.github.LlmDl:Towny:25fc18a' + compileOnly 'com.github.BenCodez:VotingPlugin:6.0' + compileOnly 'com.github.LlmDl:Towny:25fc18a' + + implementation ('io.pebbletemplates:pebble:3.1.5') { + exclude group: 'org.slf4j' + } +} + +artifacts { + archives shadowJar +} + +shadowJar { + archiveClassifier.set('') + minimize() } // automatically copy the version to plugin.yml @@ -64,8 +85,9 @@ processResources { } } -task spigot(type: Jar) { +task spigot(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from sourceSets.main.runtimeClasspath destinationDirectory = file("./spigot/plugins/") archiveFileName = "Rankup.jar" -} \ No newline at end of file +} + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf..490fda8 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4c9e569..442d913 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sun Apr 05 14:05:23 BST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cba68cc..2fe81a7 100755 --- a/gradlew +++ b/gradlew @@ -1,188 +1,183 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 15e1ee3..9109989 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -5,7 +5,7 @@ @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem -@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" diff --git a/src/main/java/sh/okx/rankup/RankupHelper.java b/src/main/java/sh/okx/rankup/RankupHelper.java index c6800e0..28b5eb9 100644 --- a/src/main/java/sh/okx/rankup/RankupHelper.java +++ b/src/main/java/sh/okx/rankup/RankupHelper.java @@ -51,11 +51,15 @@ public class RankupHelper { public void sendRankupMessages(Player player, RankElement rank) { plugin.getMessage(rank.getRank(), Message.SUCCESS_PUBLIC) .failIfEmpty() - .replaceRanks(player, rank.getRank(), rank.getNext().getRank()) + .replacePlayer(player) + .replaceOldRank(rank.getRank()) + .replaceRank(rank.getNext().getRank()) .broadcast(); plugin.getMessage(rank.getRank(), Message.SUCCESS_PRIVATE) .failIfEmpty() - .replaceRanks(player, rank.getRank(), rank.getNext().getRank()) + .replacePlayer(player) + .replaceOldRank(rank.getRank()) + .replaceRank(rank.getNext().getRank()) .send(player); } @@ -81,13 +85,15 @@ public class RankupHelper { plugin.getMessage(prestige.getRank(), Message.PRESTIGE_SUCCESS_PUBLIC) .failIfEmpty() - .replaceRanks(player, prestige.getRank(), prestige.getNext().getRank()) - .replaceFromTo(prestige.getRank()) + .replacePlayer(player) + .replaceOldRank(prestige.getRank()) + .replaceRank(prestige.getNext().getRank()) .broadcast(); plugin.getMessage(prestige.getRank(), Message.PRESTIGE_SUCCESS_PRIVATE) .failIfEmpty() - .replaceRanks(player, prestige.getRank(), prestige.getNext().getRank()) - .replaceFromTo(prestige.getRank()) + .replacePlayer(player) + .replaceOldRank(prestige.getRank()) + .replaceRank(prestige.getNext().getRank()) .send(player); } @@ -102,10 +108,10 @@ public class RankupHelper { plugin .getMessage(rank, secondsLeft > 1 ? Message.COOLDOWN_PLURAL : Message.COOLDOWN_SINGULAR) .failIfEmpty() - .replaceRanks(player, rank) - .replaceFromTo(rank) - .replace(Variable.SECONDS, cooldownSeconds) - .replace(Variable.SECONDS_LEFT, secondsLeft) + .replacePlayer(player) + .replaceRank(rank) + .replaceKey(Variable.SECONDS.toString(), cooldownSeconds) + .replaceKey(Variable.SECONDS_LEFT.toString(), secondsLeft) .send(player); return true; } @@ -151,22 +157,27 @@ public class RankupHelper { if (rankElement == null) { // check if in ladder plugin.getMessage(Message.NOT_IN_LADDER) .failIf(!message) - .replace(Variable.PLAYER, player.getName()) + .replacePlayer(player) .send(player); return false; } Rank rank = rankElement.getRank(); if (!rankElement.hasNext()) { Prestiges prestiges = plugin.getPrestiges(); - plugin.getMessage(prestiges == null || !prestiges.getByPlayer(player).hasNext() ? Message.NO_RANKUP : Message.MUST_PRESTIGE) + plugin.getMessage( + prestiges == null || !prestiges.getByPlayer(player).hasNext() ? Message.NO_RANKUP + : Message.MUST_PRESTIGE) .failIf(!message) - .replaceRanks(player, rankups.getTree().last().getRank()) + .replacePlayer(player) + .replaceRank(rankups.getTree().last().getRank()) .send(player); return false; } else if (!rank.hasRequirements(player)) { // check if they can afford it if (message) { - plugin.replaceMoneyRequirements(plugin.getMessage(rank, Message.REQUIREMENTS_NOT_MET) - .replaceRanks(player, rank, rankElement.getNext().getRank()), player, rank) + plugin.getMessage(rank, Message.REQUIREMENTS_NOT_MET) + .replacePlayer(player) + .replaceOldRank(rank) + .replaceRank(rankElement.getNext().getRank()) .send(player); } return false; @@ -198,25 +209,26 @@ public class RankupHelper { public boolean checkPrestige(Player player, boolean message) { Prestiges prestiges = plugin.getPrestiges(); RankElement prestigeElement = prestiges.getByPlayer(player); - if (prestigeElement == null || !prestigeElement.getRank().isEligible(player)) { // check if in ladder + if (prestigeElement == null || !prestigeElement.getRank() + .isEligible(player)) { // check if in ladder plugin.getMessage(Message.NOT_HIGH_ENOUGH) .failIf(!message) - .replace(Variable.PLAYER, player.getName()) + .replacePlayer(player) .send(player); return false; } else if (!prestigeElement.hasNext()) { // check if they are at the highest rank plugin.getMessage(prestigeElement.getRank(), Message.PRESTIGE_NO_PRESTIGE) .failIf(!message) - .replaceRanks(player, prestigeElement.getRank()) - .replaceFromTo(prestigeElement.getRank()) + .replacePlayer(player) + .replaceRank(prestigeElement.getRank()) .send(player); return false; } else if (!prestigeElement.getRank().hasRequirements(player)) { // check if they can afford it - plugin.replaceMoneyRequirements( - plugin.getMessage(prestigeElement.getRank(), Message.PRESTIGE_REQUIREMENTS_NOT_MET) - .failIf(!message) - .replaceRanks(player, prestigeElement.getRank(), prestigeElement.getNext().getRank()), player, prestigeElement.getRank()) - .replaceFromTo(prestigeElement.getRank()) + plugin.getMessage(prestigeElement.getRank(), Message.PRESTIGE_REQUIREMENTS_NOT_MET) + .failIf(!message) + .replacePlayer(player) + .replaceOldRank(prestigeElement.getRank()) + .replaceRank(prestigeElement.getNext().getRank()) .send(player); return false; } else if (checkCooldown(player, prestigeElement.getRank())) { diff --git a/src/main/java/sh/okx/rankup/RankupPlugin.java b/src/main/java/sh/okx/rankup/RankupPlugin.java index f7a042f..46f2f62 100644 --- a/src/main/java/sh/okx/rankup/RankupPlugin.java +++ b/src/main/java/sh/okx/rankup/RankupPlugin.java @@ -1,11 +1,9 @@ package sh.okx.rankup; import java.io.File; -import java.text.DecimalFormat; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -37,8 +35,7 @@ import sh.okx.rankup.hook.PermissionManager; import sh.okx.rankup.hook.VaultPermissionManager; import sh.okx.rankup.messages.Message; import sh.okx.rankup.messages.MessageBuilder; -import sh.okx.rankup.messages.NullMessageBuilder; -import sh.okx.rankup.messages.Variable; +import sh.okx.rankup.messages.pebble.PebbleMessageBuilder; import sh.okx.rankup.placeholders.Placeholders; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.prestige.Prestiges; @@ -88,7 +85,7 @@ import sh.okx.rankup.util.VersionChecker; public class RankupPlugin extends JavaPlugin { - public static final int CONFIG_VERSION = 8; + public static final int CONFIG_VERSION = 10; @Getter private GroupProvider permissions; @@ -132,7 +129,7 @@ public class RankupPlugin extends JavaPlugin { reload(true); - if (System.getProperty("TEST") == null) { + if (System.getProperty("RANKUP_TEST") == null) { Metrics metrics = new Metrics(this); metrics.addCustomChart(new Metrics.SimplePie("confirmation", () -> config.getString("confirmation-type", "unknown"))); @@ -235,6 +232,10 @@ public class RankupPlugin extends JavaPlugin { helper = new RankupHelper(this); } + public MessageBuilder newMessageBuilder(String message) { + return new PebbleMessageBuilder(this, message); + } + public boolean error() { return error(null); } @@ -408,7 +409,7 @@ public class RankupPlugin extends JavaPlugin { new TokensRequirement(this, "tokenmanager-tokensh"), new TokensDeductibleRequirement(this, "tokenmanager-tokens")); } - if (Bukkit.getPluginManager().isPluginEnabled("SuperbVotes")) { + if (Bukkit.getPluginManager().isPluginEnabled("SuperbVote")) { requirements.addRequirements(new SuperbVoteVotesRequirement(this)); } } @@ -445,94 +446,25 @@ public class RankupPlugin extends JavaPlugin { if (messages == null || !messages.isSet(message.getName())) { messages = this.messages; } - return MessageBuilder.of(messages, message); + return newMessageBuilder(messages.getString(message.getName())); } public MessageBuilder getMessage(Message message) { - return MessageBuilder.of(messages, message); + return newMessageBuilder(messages.getString(message.getName())); } - public MessageBuilder replaceMoneyRequirements(MessageBuilder builder, CommandSender sender, - Rank rank) { - if (builder instanceof NullMessageBuilder || rank == null) { - return builder; - } - - Requirement money = rank.getRequirement(sender instanceof Player ? (Player) sender : null, "money"); - if (money != null) { - Double amount = null; - Double total = null; - if (sender instanceof Player && rank.isIn((Player) sender)) { - if (economy != null) { - amount = money.getRemaining((Player) sender); - total = money.getTotal((Player) sender); - } - } else { - amount = money.getValueDouble(); - total = 0D; - } - if (amount != null && economy != null) { - builder.replace(Variable.MONEY_NEEDED, formatMoney(amount)); - builder.replace(Variable.MONEY, formatMoney(money.getValueDouble())); - builder.replace(Variable.MONEY_DONE, formatMoney(total - amount)); - } - } - if (sender instanceof Player) { - replaceRequirements(builder, (Player) sender, rank); - } - return builder; - } - - public MessageBuilder replaceRequirements(MessageBuilder builder, Player player, Rank rank) { - DecimalFormat simpleFormat = placeholders.getSimpleFormat(); - DecimalFormat percentFormat = placeholders.getPercentFormat(); - for (Requirement requirement : rank.getRequirements().getRequirements(player)) { - try { - replaceRequirements(builder, Variable.AMOUNT, requirement, - () -> simpleFormat.format(requirement.getTotal(player))); - if (rank.isIn(player)) { - replaceRequirements(builder, Variable.AMOUNT_NEEDED, requirement, - () -> simpleFormat.format(requirement.getRemaining(player))); - replaceRequirements(builder, Variable.PERCENT_LEFT, requirement, - () -> percentFormat.format(Math.max(0, - (requirement.getRemaining(player) / requirement.getTotal(player)) * 100))); - replaceRequirements(builder, Variable.PERCENT_DONE, requirement, - () -> percentFormat.format(Math.min(100, - (1 - (requirement.getRemaining(player) / requirement.getTotal(player))) * 100))); - replaceRequirements(builder, Variable.AMOUNT_DONE, requirement, - () -> simpleFormat - .format(requirement.getTotal(player) - requirement.getRemaining(player))); - } - } catch (NumberFormatException ignored) { - } - } - return builder; - } - - private void replaceRequirements(MessageBuilder builder, Variable variable, Requirement requirement, Supplier value) { - try { - builder.replace(variable + " " + requirement.getFullName(), value.get()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public MessageBuilder getMessage(CommandSender player, Message message, Rank oldRank, Rank rankName) { - String oldRankName; - String oldRankDisplayName; + public MessageBuilder getMessage(CommandSender player, Message message, Rank oldRank, Rank rank) { + Rank actualOldRank; if (oldRank instanceof Prestige && oldRank.getRank() == null) { - oldRankName = ((Prestige) oldRank).getFrom(); - oldRankDisplayName = rankups.getTree().last().getRank().getDisplayName(); + actualOldRank = rankups.getByName(((Prestige) oldRank).getFrom()).getRank(); } else { - oldRankName = oldRank.getRank(); - oldRankDisplayName = oldRank.getDisplayName(); + actualOldRank = oldRank; } - return replaceMoneyRequirements(getMessage(oldRank, message) - .replaceRanks(player, rankName) - .replace(Variable.OLD_RANK, oldRankName) - .replace(Variable.OLD_RANK_NAME, oldRankDisplayName), player, oldRank) - .replaceFromTo(oldRank); + return getMessage(oldRank, message) + .replacePlayer(player) + .replaceRank(rank) + .replaceOldRank(actualOldRank); } public void sendHeaderFooter(CommandSender sender, Rank rank, Message type) { @@ -540,12 +472,12 @@ public class RankupPlugin extends JavaPlugin { if (rank == null) { builder = getMessage(type) .failIfEmpty() - .replace(Variable.PLAYER, sender.getName()); + .replacePlayer(sender); } else { builder = getMessage(rank, type) .failIfEmpty() - .replaceRanks(sender, rank) - .replaceFromTo(rank); + .replacePlayer(sender) + .replaceRank(rank); } builder.send(sender); } diff --git a/src/main/java/sh/okx/rankup/commands/PrestigeCommand.java b/src/main/java/sh/okx/rankup/commands/PrestigeCommand.java index 375ca03..8155561 100644 --- a/src/main/java/sh/okx/rankup/commands/PrestigeCommand.java +++ b/src/main/java/sh/okx/rankup/commands/PrestigeCommand.java @@ -58,9 +58,10 @@ public class PrestigeCommand implements CommandExecutor { Prestige next = rankElement.getNext().getRank(); Rank nextRank = next == null ? prestiges.getTree().last().getRank() : next; - plugin.replaceMoneyRequirements(plugin.getMessage(prestige, Message.PRESTIGE_CONFIRMATION) - .replaceRanks(player, prestige, nextRank), player, prestige) - .replaceFromTo(prestige) + plugin.getMessage(prestige, Message.PRESTIGE_CONFIRMATION) + .replacePlayer(player) + .replaceOldRank(prestige) + .replaceRank(nextRank) .send(player); break; case "gui": diff --git a/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java b/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java index 210bf64..39b359a 100644 --- a/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java +++ b/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java @@ -7,6 +7,8 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.messages.Message; +import sh.okx.rankup.messages.MessageBuilder; +import sh.okx.rankup.messages.Variable; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.prestige.Prestiges; import sh.okx.rankup.ranks.RankElement; @@ -38,9 +40,12 @@ public class PrestigesCommand implements CommandExecutor { .send(sender); message = Message.PRESTIGES_INCOMPLETE; } else { - plugin.getMessage(sender, message, prestige.getRank(), next.getRank()) - .replaceFirstPrestige(prestige.getRank(), prestiges, prestige.getRank().getFrom()) - .send(sender); + MessageBuilder builder = plugin + .getMessage(sender, message, prestige.getRank(), next.getRank()); + if (prestiges.getFirst().equals(prestige.getRank())) { + builder.replaceKey(Variable.OLD_RANK.toString(), prestige.getRank().getFrom()); + } + builder.send(sender); } prestige = next; } diff --git a/src/main/java/sh/okx/rankup/commands/RankupCommand.java b/src/main/java/sh/okx/rankup/commands/RankupCommand.java index 18fbe37..47f9c71 100644 --- a/src/main/java/sh/okx/rankup/commands/RankupCommand.java +++ b/src/main/java/sh/okx/rankup/commands/RankupCommand.java @@ -58,8 +58,10 @@ public class RankupCommand implements CommandExecutor { switch (confirmationType) { case "text": confirming.put(player, System.currentTimeMillis()); - plugin.replaceMoneyRequirements(plugin.getMessage(rankElement.getRank(), Message.CONFIRMATION) - .replaceRanks(player, rankElement.getRank(), rankElement.getNext().getRank()), player, rankElement.getRank()) + plugin.getMessage(rankElement.getRank(), Message.CONFIRMATION) + .replacePlayer(player) + .replaceOldRank(rankElement.getRank()) + .replaceRank(rankElement.getNext().getRank()) .send(player); break; case "gui": diff --git a/src/main/java/sh/okx/rankup/gui/Gui.java b/src/main/java/sh/okx/rankup/gui/Gui.java index c77fb5c..c0bbebe 100644 --- a/src/main/java/sh/okx/rankup/gui/Gui.java +++ b/src/main/java/sh/okx/rankup/gui/Gui.java @@ -26,6 +26,7 @@ import sh.okx.rankup.util.ItemUtil; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Gui implements InventoryHolder { + @Getter private final boolean returnToRanksGui; @Getter @@ -37,7 +38,8 @@ public class Gui implements InventoryHolder { @Getter private boolean prestige; - public static Gui of(Player player, Rank oldRank, Rank rank, RankupPlugin plugin, boolean returnToRanksGui) { + public static Gui of(Player player, Rank oldRank, Rank rank, RankupPlugin plugin, + boolean returnToRanksGui) { Gui gui = new Gui(returnToRanksGui); gui.prestige = oldRank instanceof Prestige; @@ -45,15 +47,19 @@ public class Gui implements InventoryHolder { String basePath = type + ".gui"; ConfigurationSection config = plugin.getSection(oldRank, basePath); if (config == null) { - plugin.getLogger().severe("You must update your config.yml and locale/en.yml to be able to use the GUI! Your configuration files are outdated."); + plugin.getLogger().severe( + "You must update your config.yml and locale/en.yml to be able to use the GUI! Your configuration files are outdated."); return null; } ItemStack[] items = new ItemStack[config.getInt("rows", 1) * 9]; - ItemStack fill = getItem(plugin, plugin.getSection(oldRank, basePath + ".fill"), player, oldRank, rank); - ItemStack cancel = getItem(plugin, plugin.getSection(oldRank, basePath + ".cancel"), player, oldRank, rank); - ItemStack rankup = getItem(plugin, plugin.getSection(oldRank, basePath + ".rankup"), player, oldRank, rank); + ItemStack fill = getItem(plugin, plugin.getSection(oldRank, basePath + ".fill"), player, + oldRank, rank); + ItemStack cancel = getItem(plugin, plugin.getSection(oldRank, basePath + ".cancel"), player, + oldRank, rank); + ItemStack rankup = getItem(plugin, plugin.getSection(oldRank, basePath + ".rankup"), player, + oldRank, rank); addItem(items, plugin.getSection(oldRank, basePath + ".rankup"), rankup); addItem(items, plugin.getSection(oldRank, basePath + ".cancel"), cancel); @@ -63,26 +69,30 @@ public class Gui implements InventoryHolder { gui.cancel = cancel; Inventory inventory = Bukkit.createInventory(gui, items.length, - Colour.translate(plugin.replaceMoneyRequirements( + Colour.translate( plugin.getMessage(oldRank, gui.prestige ? Message.PRESTIGE_TITLE : Message.TITLE) - .replaceRanks(player, oldRank, rank) - .replaceFromTo(oldRank), player, oldRank).toString())); + .replacePlayer(player) + .replaceOldRank(oldRank) + .replaceRank(rank).toString(player))); inventory.setContents(items); gui.inventory = inventory; return gui; } - public static ItemStack getItem(RankupPlugin plugin, ConfigurationSection section, Player player, RankElement element) { + public static ItemStack getItem(RankupPlugin plugin, ConfigurationSection section, Player player, + RankElement element) { if (element == null) { return getItem(plugin, section, player, null, null); } else { RankElement next = element.getNext(); - return getItem(plugin, section, player, element.getRank(), (next == null ? element : next).getRank()); + return getItem(plugin, section, player, element.getRank(), + (next == null ? element : next).getRank()); } } @SuppressWarnings("deprecation") - public static ItemStack getItem(RankupPlugin plugin, ConfigurationSection section, Player player, Rank oldRank, Rank rank) { + public static ItemStack getItem(RankupPlugin plugin, ConfigurationSection section, Player player, + Rank oldRank, Rank rank) { if (section == null) { return null; } @@ -111,23 +121,26 @@ public class Gui implements InventoryHolder { ItemMeta meta = item.getItemMeta(); if (section.contains("lore")) { - meta.setLore(Arrays.stream(format(plugin, section.getString("lore"), player, oldRank, rank).split("\n")) + meta.setLore(Arrays + .stream(format(plugin, section.getString("lore"), player, oldRank, rank).split("\n")) .map(string -> ChatColor.RESET + string) .collect(Collectors.toList())); } if (section.contains("name")) { - meta.setDisplayName(ChatColor.RESET + format(plugin, section.getString("name"), player, oldRank, rank)); + meta.setDisplayName( + ChatColor.RESET + format(plugin, section.getString("name"), player, oldRank, rank)); } item.setItemMeta(meta); return item; } - private static String format(RankupPlugin plugin, String message, Player player, Rank oldRank, Rank rank) { - MessageBuilder builder = new MessageBuilder(message); + private static String format(RankupPlugin plugin, String message, Player player, Rank oldRank, + Rank rank) { + MessageBuilder builder = plugin.newMessageBuilder(message); if (oldRank != null && rank != null) { - builder = builder.replaceRanks(player, oldRank, rank); + builder = builder.replacePlayer(player).replaceOldRank(oldRank).replaceRank(rank); } - return Colour.translate(plugin.replaceMoneyRequirements(builder, player, oldRank).toString()); + return builder.toString(player); } private static void addItem(ItemStack[] items, ConfigurationSection section, ItemStack item) { diff --git a/src/main/java/sh/okx/rankup/messages/MessageBuilder.java b/src/main/java/sh/okx/rankup/messages/MessageBuilder.java index 1841fd2..859627e 100644 --- a/src/main/java/sh/okx/rankup/messages/MessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/MessageBuilder.java @@ -1,156 +1,30 @@ package sh.okx.rankup.messages; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import me.clip.placeholderapi.PlaceholderAPI; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; -import sh.okx.rankup.prestige.Prestige; -import sh.okx.rankup.prestige.Prestiges; import sh.okx.rankup.ranks.Rank; -import sh.okx.rankup.util.Colour; -public class MessageBuilder { - private String message; +public interface MessageBuilder { + MessageBuilder replaceKey(String key, Object value); + MessageBuilder replacePlayer(CommandSender sender); + MessageBuilder replaceRank(Rank rank); + MessageBuilder replaceOldRank(Rank rank); - public MessageBuilder(String message) { - this.message = message; - } + void send(CommandSender sender); + void broadcast(); - public static MessageBuilder of(ConfigurationSection config, Message message) { - return MessageBuilder.of(config, message.getName()); - } + String toString(); - private static MessageBuilder of(ConfigurationSection config, String message) { - String string = config.getString(message); - Objects.requireNonNull(string, "Configuration message '" + message + "' not found!"); - return new MessageBuilder(Colour.translate(string)); - } - - public MessageBuilder replace(Variable variable, Object value) { - return replace(variable.name(), value); - } - - public MessageBuilder replace(String name, Object value) { - if (value == null) { - return this; - } - Pattern pattern = Pattern.compile("\\{" + name + "}", Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher(message); - this.message = matcher.replaceAll(String.valueOf(value)); - return this; - } - - public MessageBuilder replaceFirstPrestige(Rank rank, Prestiges prestiges, String with) { - if (prestiges != null && prestiges.getFirst().equals(rank)) { - replace(Variable.OLD_RANK, with); - } - return this; - } - - @Deprecated - public MessageBuilder replaceRanks(CommandSender player, String rankName) { - replace(Variable.PLAYER, player.getName()); - replaceRanks(rankName); - return this; - } - - @Deprecated - public MessageBuilder replaceRanks(CommandSender player, Rank oldRank, String rankName) { - replace(Variable.PLAYER, player.getName()); - replaceRanks(oldRank, rankName); - return this; - } - - public MessageBuilder replaceRanks(CommandSender player, Rank rank) { - replace(Variable.PLAYER, player.getName()); - replaceRanks(rank); - return this; - } - - public MessageBuilder replaceRanks(CommandSender player, Rank oldRank, Rank rank) { - replace(Variable.PLAYER, player.getName()); - replaceRanks(oldRank, rank); - return this; - } - - @Deprecated - public MessageBuilder replaceRanks(String rankName) { - replace(Variable.RANK, rankName); - return this; - } - - public MessageBuilder replaceRanks(Rank rank) { - replace(Variable.RANK, rank.getRank()); - replace(Variable.RANK_NAME, rank.getDisplayName()); - return this; - } - - @Deprecated - public MessageBuilder replaceRanks(Rank oldRank, String rankName) { - replaceRanks(rankName); - replace(Variable.OLD_RANK, oldRank.getRank()); - replace(Variable.OLD_RANK_NAME, oldRank.getDisplayName()); - return this; - } - - public MessageBuilder replaceRanks(Rank oldRank, Rank rank) { - replaceRanks(rank); - replace(Variable.OLD_RANK, oldRank.getRank()); - replace(Variable.OLD_RANK_NAME, oldRank.getDisplayName()); - return this; - } - - public MessageBuilder replaceFromTo(Rank rank) { - if (rank instanceof Prestige) { - Prestige prestige = (Prestige) rank; - replace(Variable.FROM, prestige.getFrom()); - replace(Variable.TO, prestige.getTo()); - } - return this; - } - - /** - * Fails the MessageBuilder if the message is empty. - * if this fails, all subsequent calls to that MessageBuilder will do nothing - * @return a NullMessageBuilder if the message is empty, itself otherwise - */ - public MessageBuilder failIfEmpty() { - return failIf(message.isEmpty()); - } - - public MessageBuilder failIf(boolean value) { - if (value) { + MessageBuilder failIfEmpty(); + default MessageBuilder failIf(boolean b) { + if (b) { return new NullMessageBuilder(); } else { return this; } } - public void send(CommandSender sender) { - String msg = message; - if (sender instanceof Player && Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { - msg = PlaceholderAPI.setPlaceholders((Player) sender, msg); - } - sender.sendMessage(msg); - } - - /** - * Sends the message to all players - * ie, calls MessageBuilder#send(Player) for all players online, and sends the message in the console. - */ - public void broadcast() { - for (Player player : Bukkit.getOnlinePlayers()) { - send(player); - } - send(Bukkit.getConsoleSender()); - } - - @Override - public String toString() { - return message; + default String toString(Player player) { + return toString(); } } diff --git a/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java index 373402f..1912cc5 100644 --- a/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java @@ -1,35 +1,50 @@ package sh.okx.rankup.messages; import org.bukkit.command.CommandSender; +import sh.okx.rankup.ranks.Rank; /** * A no-op implementation of MessageBuilder */ -public class NullMessageBuilder extends MessageBuilder { - NullMessageBuilder() { - super(null); - } +public class NullMessageBuilder implements MessageBuilder { @Override - public MessageBuilder failIf(boolean value) { + public MessageBuilder replaceKey(String key, Object value) { return this; } @Override - public MessageBuilder replace(Variable variable, Object value) { + public MessageBuilder replacePlayer(CommandSender sender) { + return this; + } + + @Override + public MessageBuilder replaceRank(Rank rank) { + return this; + } + + @Override + public MessageBuilder replaceOldRank(Rank rank) { return this; } @Override public void send(CommandSender sender) { + } @Override public void broadcast() { + } @Override public String toString() { return null; } + + @Override + public MessageBuilder failIfEmpty() { + return null; + } } diff --git a/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java new file mode 100644 index 0000000..9a87d6e --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java @@ -0,0 +1,119 @@ +package sh.okx.rankup.messages; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import sh.okx.rankup.prestige.Prestige; +import sh.okx.rankup.prestige.Prestiges; +import sh.okx.rankup.ranks.Rank; +import sh.okx.rankup.util.Colour; + +public class StringMessageBuilder implements MessageBuilder { + + private String message; + + public StringMessageBuilder(String message) { + this.message = message; + } + + public static StringMessageBuilder of(ConfigurationSection config, Message message) { + return StringMessageBuilder.of(config, message.getName()); + } + + private static StringMessageBuilder of(ConfigurationSection config, String message) { + String string = config.getString(message); + Objects.requireNonNull(string, "Configuration message '" + message + "' not found!"); + return new StringMessageBuilder(Colour.translate(string)); + } + + public StringMessageBuilder replace(Variable variable, Object value) { + return replaceKey(variable.name(), value); + } + + @Override + public StringMessageBuilder replaceKey(String name, Object value) { + if (value == null) { + return this; + } + Pattern pattern = Pattern.compile("\\{" + name + "}", Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(message); + this.message = matcher.replaceAll(String.valueOf(value)); + return this; + } + + public StringMessageBuilder replaceFirstPrestige(Rank rank, Prestiges prestiges, String with) { + if (prestiges != null && prestiges.getFirst().equals(rank)) { + replace(Variable.OLD_RANK, with); + } + return this; + } + + /** + * Fails the MessageBuilder if the message is empty. if this fails, all subsequent calls to that + * MessageBuilder will do nothing + * + * @return a NullMessageBuilder if the message is empty, itself otherwise + */ + public MessageBuilder failIfEmpty() { + return failIf(message.isEmpty()); + } + + public MessageBuilder failIf(boolean value) { + if (value) { + return new NullMessageBuilder(); + } else { + return this; + } + } + + @Override + public MessageBuilder replacePlayer(CommandSender sender) { + return replace(Variable.PLAYER, sender.getName()); + } + + @Override + public MessageBuilder replaceRank(Rank rank) { + return replace(Variable.RANK, rank.getRank()) + .replace(Variable.RANK_NAME, rank.getDisplayName()); + } + + @Override + public MessageBuilder replaceOldRank(Rank rank) { + if (rank instanceof Prestige) { + Prestige prestige = (Prestige) rank; + replace(Variable.FROM, prestige.getFrom()); + replace(Variable.TO, prestige.getTo()); + } + return replace(Variable.OLD_RANK, rank.getRank()) + .replace(Variable.OLD_RANK_NAME, rank.getDisplayName()); + } + + public void send(CommandSender sender) { + String msg = message; + if (sender instanceof Player && Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + msg = PlaceholderAPI.setPlaceholders((Player) sender, msg); + } + sender.sendMessage(msg); + } + + /** + * Sends the message to all players ie, calls MessageBuilder#send(Player) for all players online, + * and sends the message in the console. + */ + public void broadcast() { + for (Player player : Bukkit.getOnlinePlayers()) { + send(player); + } + send(Bukkit.getConsoleSender()); + } + + @Override + public String toString() { + return message; + } +} diff --git a/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java new file mode 100644 index 0000000..98f88c1 --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java @@ -0,0 +1,141 @@ +package sh.okx.rankup.messages.pebble; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import sh.okx.rankup.RankupPlugin; +import sh.okx.rankup.messages.MessageBuilder; +import sh.okx.rankup.messages.NullMessageBuilder; +import sh.okx.rankup.placeholders.Placeholders; +import sh.okx.rankup.prestige.Prestige; +import sh.okx.rankup.ranks.Rank; +import sh.okx.rankup.text.TextProcessor; +import sh.okx.rankup.text.TextProcessorBuilder; +import sh.okx.rankup.text.pebble.PebbleOptions; + +public class PebbleMessageBuilder implements MessageBuilder { + + private final RankupPlugin plugin; + private final String message; + private final Map context = new HashMap<>(); + private final Map> lastMinuteContext = new HashMap<>(); + + public PebbleMessageBuilder(RankupPlugin plugin, String message) { + this.plugin = plugin; + this.message = message; + replaceInitial(); + } + + private void replaceInitial() { + Function lastMinute = player -> { + List ranks = new ArrayList<>(); + for (Rank rank : plugin.getRankups().getTree()) { + ranks.add(new RankContext(plugin, player, rank)); + } + return ranks; + }; + lastMinuteContext.put("ranks", lastMinute); + lastMinuteContext.put("player", HumanEntity::getName); + } + + @Override + public PebbleMessageBuilder replaceKey(String key, Object value) { + context.put(key, value); + return this; + } + + @Override + public PebbleMessageBuilder replacePlayer(CommandSender sender) { + context.put("player", sender.getName()); + return this; + } + + @Override + public PebbleMessageBuilder replaceRank(Rank rank) { + lastMinuteContext.put("next", player -> new RankContext(plugin, player, rank)); + return this; + } + + @Override + public PebbleMessageBuilder replaceOldRank(Rank rank) { + Function object; + if (rank instanceof Prestige) { + object = player -> new PrestigeContext(plugin, player, (Prestige) rank); + } else { + object = player -> new RankContext(plugin, player, rank); + } + lastMinuteContext.put("rank", object); + return this; + } + + @Override + public void send(CommandSender sender) { + Player player = null; + if (sender instanceof Player) { + player = (Player) sender; + } + sender.sendMessage(processor(player).process(message)); + } + + @Override + public void broadcast() { + for (Player player : Bukkit.getOnlinePlayers()) { + send(player); + } + send(Bukkit.getConsoleSender()); + } + + @Override + public String toString() { + return processor(null).process(message); + } + + @Override + public String toString(Player player) { + return processor(player).process(message); + } + + private TextProcessor processor(Player player) { + Map context = getContext(player); + PebbleOptions options = getOptions(); + return new TextProcessorBuilder() + .legacy(context, options) + .papi(player) + .pebble(context, options) + .papi(player) + .colour() + .create(); + } + + private Map getContext(Player player) { + Map context = new HashMap<>(this.context); + if (player != null) { + for (Map.Entry> lastMinute : lastMinuteContext.entrySet()) { + context.putIfAbsent(lastMinute.getKey(), lastMinute.getValue().apply(player)); + } + } + return context; + } + + @Override + public MessageBuilder failIfEmpty() { + if (message.isEmpty()) { + return new NullMessageBuilder(); + } else { + return this; + } + } + + private PebbleOptions getOptions() { + Placeholders placeholders = plugin.getPlaceholders(); + return new PebbleOptions(placeholders.getMoneyFormat(), + placeholders.getPercentFormat(), + placeholders.getSimpleFormat()); + } +} diff --git a/src/main/java/sh/okx/rankup/messages/pebble/PrestigeContext.java b/src/main/java/sh/okx/rankup/messages/pebble/PrestigeContext.java new file mode 100644 index 0000000..60af03d --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/pebble/PrestigeContext.java @@ -0,0 +1,24 @@ +package sh.okx.rankup.messages.pebble; + + +import org.bukkit.entity.Player; +import sh.okx.rankup.RankupPlugin; +import sh.okx.rankup.prestige.Prestige; + +public class PrestigeContext extends RankContext { + + private final Prestige rank; + + public PrestigeContext(RankupPlugin plugin, Player player, Prestige rank) { + super(plugin, player, rank); + this.rank = rank; + } + + public String getFrom() { + return rank.getFrom(); + } + + public String getTo() { + return rank.getTo(); + } +} diff --git a/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java b/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java new file mode 100644 index 0000000..b32ee09 --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java @@ -0,0 +1,78 @@ +package sh.okx.rankup.messages.pebble; + +import java.util.ArrayList; +import java.util.List; +import org.bukkit.entity.Player; +import sh.okx.rankup.RankupPlugin; +import sh.okx.rankup.ranks.Rank; +import sh.okx.rankup.ranks.RankTree; +import sh.okx.rankup.requirements.Requirement; + +public class RankContext { + private final RankupPlugin plugin; + private final Player player; + private final Rank rank; + + public RankContext(RankupPlugin plugin, Player player, Rank rank) { + this.plugin = plugin; + this.player = player; + this.rank = rank; + } + + public String getRank() { + return rank.getRank(); + } + + public String getName() { + return rank.getDisplayName(); + } + + public RequirementContext getRequirement(String requirement) { + return new RequirementContext(player, rank.getRequirement(player, requirement)); + } + + public RequirementContext getRequirement(String requirement, String sub) { + return new RequirementContext(player, rank.getRequirement(player, requirement + "#" + sub)); + } + + public RequirementContext getReq(String requirement) { + return getRequirement(requirement); + } + + public RequirementContext getReq(String requirement, String sub) { + return getRequirement(requirement, sub); + } + + public List getRequirements() { + List list = new ArrayList<>(); + for (Requirement requirement : rank.getRequirements().getRequirements(player)) { + list.add(new RequirementContext(player, requirement)); + } + return list; + } + + public boolean getDone() { + for (RequirementContext context : getRequirements()) { + if (!context.getDone()) { + return false; + } + } + return true; + } + + public int getIndex() { + RankTree tree = plugin.getRankups().getTree(); + int index = 0; + for (Rank rank : tree) { + if (rank == this.rank) { + return index; + } + index++; + } + return -1; + } + + public String toString() { + return rank.getRank(); + } +} diff --git a/src/main/java/sh/okx/rankup/messages/pebble/RequirementContext.java b/src/main/java/sh/okx/rankup/messages/pebble/RequirementContext.java new file mode 100644 index 0000000..4979903 --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/pebble/RequirementContext.java @@ -0,0 +1,43 @@ +package sh.okx.rankup.messages.pebble; + +import org.bukkit.entity.Player; +import sh.okx.rankup.requirements.Requirement; + +public class RequirementContext { + + private final Player player; + private final Requirement requirement; + + public RequirementContext(Player player, Requirement requirement) { + this.player = player; + this.requirement = requirement; + } + + public double getTotal() { + return requirement.getTotal(player); + } + + public boolean getDone() { + return requirement.check(player); + } + + public double getRemaining() { + return requirement.getRemaining(player); + } + + public double getProgress() { + return requirement.getTotal(player) - requirement.getRemaining(player); + } + + public String getName() { + return requirement.getName(); + } + + public double getPercent() { + return getProgress() / getTotal(); + } + + public String toString() { + return "Requirement[" + requirement.getFullName() + "]"; + } +} diff --git a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java index 36e3563..777658c 100644 --- a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java +++ b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java @@ -47,19 +47,19 @@ public class RankupExpansion implements Expansion { replacePattern(parts[1]), parts.length > 2 ? parts[2] : ""); } else if (params.startsWith("rank_requirement_")) { String[] parts = params.split("_", 5); - return getPlaceholderRequirement(player, rankups.getByName(parts[2]), + return getPlaceholderRequirement(player, rankups.getRankByName(parts[2]), replacePattern(parts[3]), parts.length > 4 ? parts[4] : ""); // return placeholders.getSimpleFormat().format(orElse(rankups.getByName(parts[2]).getRequirement(parts[3]), Requirement::getValueDouble, 0)); } else if (params.startsWith("rank_money_")) { String[] parts = params.split("_", 4); - double amount = Objects.requireNonNull(rankups.getByName(parts[2]), "Rankup " + parts[2] + " does not exist").getRequirement(player, "money").getValueDouble(); + double amount = Objects.requireNonNull(rankups.getRankByName(parts[2]), "Rankup " + parts[2] + " does not exist").getRequirement(player, "money").getValueDouble(); if (parts.length > 3 && parts[3].equalsIgnoreCase("left")) { amount = amount - plugin.getEconomy().getBalance(player); } return plugin.formatMoney(Math.max(0, amount)); } else if (params.startsWith("status_")) { String[] parts = params.split("_", 2); - Rank statusRank = rankups.getByName(parts[1]); + Rank statusRank = rankups.getRankByName(parts[1]); if (statusRank == null) { return null; diff --git a/src/main/java/sh/okx/rankup/prestige/Prestige.java b/src/main/java/sh/okx/rankup/prestige/Prestige.java index 3baa600..034efcb 100644 --- a/src/main/java/sh/okx/rankup/prestige/Prestige.java +++ b/src/main/java/sh/okx/rankup/prestige/Prestige.java @@ -9,7 +9,7 @@ import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; -import sh.okx.rankup.messages.MessageBuilder; +import sh.okx.rankup.messages.pebble.PebbleMessageBuilder; import sh.okx.rankup.ranks.Rank; import sh.okx.rankup.ranks.requirements.ListRankRequirements; import sh.okx.rankup.ranks.requirements.RankRequirements; @@ -45,9 +45,10 @@ public class Prestige extends Rank { @Override public void runCommands(Player player, Rank next) { for (String command : commands) { - String string = new MessageBuilder(command) - .replaceRanks(player, this, next) - .replaceFromTo(this) + String string = new PebbleMessageBuilder(this.plugin, command) + .replacePlayer(player) + .replaceOldRank(this) + .replaceRank(next) .toString(); if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { string = PlaceholderAPI.setPlaceholders(player, string); diff --git a/src/main/java/sh/okx/rankup/ranks/Rank.java b/src/main/java/sh/okx/rankup/ranks/Rank.java index b2f81c9..9fed31e 100644 --- a/src/main/java/sh/okx/rankup/ranks/Rank.java +++ b/src/main/java/sh/okx/rankup/ranks/Rank.java @@ -1,20 +1,17 @@ package sh.okx.rankup.ranks; +import java.util.List; import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; -import me.clip.placeholderapi.PlaceholderAPI; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; -import sh.okx.rankup.messages.MessageBuilder; import sh.okx.rankup.ranks.requirements.RankRequirements; import sh.okx.rankup.requirements.Requirement; -import java.util.List; - @EqualsAndHashCode @RequiredArgsConstructor(access = AccessLevel.PROTECTED) public class Rank { @@ -50,10 +47,7 @@ public class Rank { public void runCommands(Player player, Rank next) { for (String command : commands) { - String string = new MessageBuilder(command).replaceRanks(player, this, next).toString(); - if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { - string = PlaceholderAPI.setPlaceholders(player, string); - } + String string = plugin.newMessageBuilder(command).replacePlayer(player).replaceOldRank(this).replaceRank(next).toString(player); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), string); } } diff --git a/src/main/java/sh/okx/rankup/ranks/RankList.java b/src/main/java/sh/okx/rankup/ranks/RankList.java index f0546d8..cf85f90 100644 --- a/src/main/java/sh/okx/rankup/ranks/RankList.java +++ b/src/main/java/sh/okx/rankup/ranks/RankList.java @@ -91,7 +91,7 @@ public abstract class RankList { return tree.getFirst().getRank(); } - public T getByName(String name) { + public T getRankByName(String name) { if (name == null) { return null; } @@ -103,6 +103,20 @@ public abstract class RankList { return null; } + public RankElement getByName(String name) { + if (name == null) { + return null; + } + List> rankElements = tree.asList(); + for (RankElement rank : rankElements) { + if (name.equalsIgnoreCase(rank.getRank().getRank())) { + return rank; + } + } + return null; + } + + public RankElement getByPlayer(Player player) { List> list = tree.asList(); Collections.reverse(list); diff --git a/src/main/java/sh/okx/rankup/requirements/requirement/mcmmo/McMMOSkillUtil.java b/src/main/java/sh/okx/rankup/requirements/requirement/mcmmo/McMMOSkillUtil.java index b792433..3b9d974 100644 --- a/src/main/java/sh/okx/rankup/requirements/requirement/mcmmo/McMMOSkillUtil.java +++ b/src/main/java/sh/okx/rankup/requirements/requirement/mcmmo/McMMOSkillUtil.java @@ -2,10 +2,9 @@ package sh.okx.rankup.requirements.requirement.mcmmo; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.util.player.UserManager; -import org.bukkit.entity.Player; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.bukkit.entity.Player; /** * Because mcMMO like changing the name of their skill types. diff --git a/src/main/java/sh/okx/rankup/text/ChainedTextProcessor.java b/src/main/java/sh/okx/rankup/text/ChainedTextProcessor.java new file mode 100644 index 0000000..8e9c303 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/ChainedTextProcessor.java @@ -0,0 +1,17 @@ +package sh.okx.rankup.text; + +public class ChainedTextProcessor implements TextProcessor { + private final TextProcessor[] processors; + + public ChainedTextProcessor(TextProcessor... processors) { + this.processors = processors; + } + + @Override + public String process(String string) { + for (TextProcessor processor : processors) { + string = processor.process(string); + } + return string; + } +} diff --git a/src/main/java/sh/okx/rankup/text/ColourTextProcessor.java b/src/main/java/sh/okx/rankup/text/ColourTextProcessor.java new file mode 100644 index 0000000..47047a0 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/ColourTextProcessor.java @@ -0,0 +1,11 @@ +package sh.okx.rankup.text; + +import sh.okx.rankup.util.Colour; + +public class ColourTextProcessor implements TextProcessor { + + @Override + public String process(String string) { + return Colour.translate(string); + } +} diff --git a/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java b/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java new file mode 100644 index 0000000..40099b9 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java @@ -0,0 +1,107 @@ +package sh.okx.rankup.text; + +import java.util.Map; +import java.util.function.Function; +import sh.okx.rankup.messages.pebble.RankContext; +import sh.okx.rankup.text.pebble.PebbleOptions; + +public class LegacyTextProcessor implements TextProcessor { + + private final Map pebbleContext; + private final PebbleOptions options; + + public LegacyTextProcessor(Map pebbleContext, PebbleOptions options) { + this.pebbleContext = pebbleContext; + this.options = options; + } + + + @Override + public String process(String string) { + StringBuilder output = new StringBuilder(); + StringBuilder buffer = new StringBuilder(); + boolean isPlaceholder = false; + + char[] chars = string.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (c == '{') { + if (i + 1 < chars.length) { + if (chars[i + 1] != '{') { + isPlaceholder = true; + } else { + output.append(c).append(chars[i + 1]); + i++; + } + } else { + output.append(c); + } + } else if (c == '}' && isPlaceholder) { + output.append(replacePlaceholder(buffer.toString())); + buffer.delete(0, buffer.length()); + isPlaceholder = false; + } else if (isPlaceholder) { + buffer.append(c); + } else { + output.append(c); + } + } + + return output.toString(); + } + + private String replacePlaceholder(String p) { + if ("player".equalsIgnoreCase(p)) { + return get("player", p); + } else if ("old_rank".equalsIgnoreCase(p)) { + return get("rank", p, o -> ((RankContext) o).getRank()); + } else if ("rank".equalsIgnoreCase(p)) { + return get("next", p, o -> ((RankContext) o).getRank()); + } else if ("old_rank_name".equalsIgnoreCase(p)) { + return get("rank", p, o -> ((RankContext) o).getName()); + } else if ("rank_name".equalsIgnoreCase(p)) { + return get("next", p, o -> ((RankContext) o).getName()); + } else if ("money".equalsIgnoreCase(p)) { + return get("rank", p, o -> this.options.getMoneyFormat().format( + ((RankContext) o).getReq("money").getTotal())); + } else if ("money_needed".equalsIgnoreCase(p)) { + return get("rank", p, o -> this.options.getMoneyFormat().format( + ((RankContext) o).getReq("money").getRemaining())); + } else if (p.toLowerCase().startsWith("amount ")) { + String requirement = p.substring("amount ".length()); + return get("rank", p, o -> this.options.getSimpleFormat() + .format(((RankContext) o).getReq(requirement).getTotal())); + } else if (p.toLowerCase().startsWith("amount_done ")) { + String requirement = p.substring("amount_done ".length()); + return get("rank", p, o -> this.options.getSimpleFormat() + .format(((RankContext) o).getReq(requirement).getProgress())); + } else if (p.toLowerCase().startsWith("amount_needed ")) { + String requirement = p.substring("amount_needed ".length()); + return get("rank", p, o -> this.options.getSimpleFormat() + .format(((RankContext) o).getReq(requirement).getRemaining())); + } else if (p.toLowerCase().startsWith("percent_done ")) { + String requirement = p.substring("percent_done ".length()); + return get("rank", p, o -> this.options.getPercentFormat() + .format(((RankContext) o).getReq(requirement).getPercent() * 100)); + } else if (p.toLowerCase().startsWith("percent_left ")) { + String requirement = p.substring("percent_left ".length()); + return get("rank", p, o -> this.options.getPercentFormat() + .format(100 - ((RankContext) o).getReq(requirement).getPercent() * 100)); + } + + return get(p, "{" + p + "}"); + } + + private String get(String key, String def) { + return get(key, def, String::valueOf); + } + + private String get(String key, String def, Function mapper) { + Object val = pebbleContext.get(key); + if (val == null) { + return def; + } else { + return mapper.apply(val); + } + } +} diff --git a/src/main/java/sh/okx/rankup/text/PlaceholderApiTextProcessor.java b/src/main/java/sh/okx/rankup/text/PlaceholderApiTextProcessor.java new file mode 100644 index 0000000..79707fa --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/PlaceholderApiTextProcessor.java @@ -0,0 +1,23 @@ +package sh.okx.rankup.text; + +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class PlaceholderApiTextProcessor implements TextProcessor { + + private final Player player; + + public PlaceholderApiTextProcessor(Player player) { + this.player = player; + } + + @Override + public String process(String string) { + if (player == null || !Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + return string; + } else { + return PlaceholderAPI.setPlaceholders(player, string); + } + } +} diff --git a/src/main/java/sh/okx/rankup/text/TextProcessor.java b/src/main/java/sh/okx/rankup/text/TextProcessor.java new file mode 100644 index 0000000..2a44a51 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/TextProcessor.java @@ -0,0 +1,5 @@ +package sh.okx.rankup.text; + +public interface TextProcessor { + String process(String string); +} diff --git a/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java b/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java new file mode 100644 index 0000000..88a9c69 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java @@ -0,0 +1,38 @@ +package sh.okx.rankup.text; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; +import sh.okx.rankup.text.pebble.PebbleOptions; +import sh.okx.rankup.text.pebble.PebbleTextProcessor; + +public class TextProcessorBuilder { + + private final List processors = new ArrayList<>(); + + public TextProcessorBuilder colour() { + processors.add(new ColourTextProcessor()); + return this; + } + + public TextProcessorBuilder pebble(Map context, PebbleOptions options) { + processors.add(new PebbleTextProcessor(context, options)); + return this; + } + + public TextProcessorBuilder papi(@Nullable Player player) { + processors.add(new PlaceholderApiTextProcessor(player)); + return this; + } + + public TextProcessorBuilder legacy(Map context, PebbleOptions options) { + processors.add(new LegacyTextProcessor(context, options)); + return this; + } + + public TextProcessor create() { + return new ChainedTextProcessor(processors.toArray(new TextProcessor[0])); + } +} diff --git a/src/main/java/sh/okx/rankup/text/pebble/DecimalFormatFilter.java b/src/main/java/sh/okx/rankup/text/pebble/DecimalFormatFilter.java new file mode 100644 index 0000000..c02b220 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/pebble/DecimalFormatFilter.java @@ -0,0 +1,38 @@ +package sh.okx.rankup.text.pebble; + +import com.mitchellbosecke.pebble.error.PebbleException; +import com.mitchellbosecke.pebble.extension.Filter; +import com.mitchellbosecke.pebble.template.EvaluationContext; +import com.mitchellbosecke.pebble.template.PebbleTemplate; +import java.text.DecimalFormat; +import java.util.List; +import java.util.Map; + +public class DecimalFormatFilter implements Filter { + + private final DecimalFormat format; + + public DecimalFormatFilter(DecimalFormat format) { + this.format = format; + } + + @Override + public List getArgumentNames() { + return null; + } + + @Override + public Object apply(Object input, Map args, PebbleTemplate self, + EvaluationContext context, int lineNumber) throws PebbleException { + if (input == null) { + return null; + } + if (!(input instanceof Number)) { + throw new PebbleException(null, "The input for the 'DecimalFormatFilter' filter has to be a number.", + lineNumber, self.getName()); + } + + Number number = (Number) input; + return this.format.format(number); + } +} diff --git a/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java b/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java new file mode 100644 index 0000000..4490ca7 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java @@ -0,0 +1,11 @@ +package sh.okx.rankup.text.pebble; + +import java.text.DecimalFormat; +import lombok.Data; + +@Data +public class PebbleOptions { + private final DecimalFormat moneyFormat; + private final DecimalFormat percentFormat; + private final DecimalFormat simpleFormat; +} diff --git a/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java b/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java new file mode 100644 index 0000000..85208b2 --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java @@ -0,0 +1,54 @@ +package sh.okx.rankup.text.pebble; + +import com.mitchellbosecke.pebble.PebbleEngine; +import com.mitchellbosecke.pebble.extension.AbstractExtension; +import com.mitchellbosecke.pebble.extension.Filter; +import com.mitchellbosecke.pebble.loader.StringLoader; +import java.io.IOException; +import java.io.StringWriter; +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Map; +import sh.okx.rankup.text.TextProcessor; + +public class PebbleTextProcessor implements TextProcessor { + + private final Map context; + private final PebbleOptions options; + + public PebbleTextProcessor(Map context, PebbleOptions options) { + this.context = context; + this.options = options; + } + + @Override + public String process(String string) { + PebbleEngine engine = new PebbleEngine.Builder().autoEscaping(false).extension( + new AbstractExtension() { + @Override + public Map getFilters() { + Map filters = new HashMap<>(); + if (options != null) { + DecimalFormat moneyFormat = options.getMoneyFormat(); + if (moneyFormat != null) filters.put("money", new DecimalFormatFilter(moneyFormat)); + + DecimalFormat percentFormat = options.getPercentFormat(); + if (percentFormat != null) filters.put("percent", new DecimalFormatFilter(percentFormat)); + + DecimalFormat simpleFormat = options.getSimpleFormat(); + if (simpleFormat != null) filters.put("simple", new DecimalFormatFilter(simpleFormat)); + } + return filters; + } + }) + .loader(new StringLoader()).build(); + StringWriter writer = new StringWriter(); + try { + engine.getTemplate(string).evaluate(writer, context); + return writer.toString(); + } catch (IOException e) { + e.printStackTrace(); + return string; + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index beb731f..1937823 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,5 @@ # this is used for letting you know that you need to update/change your config file -version: 9 +version: 10 # the locale to use for messages # all messages can be customised but this allows you to diff --git a/src/main/resources/locale/en.yml b/src/main/resources/locale/en.yml index 8900d05..2474396 100644 --- a/src/main/resources/locale/en.yml +++ b/src/main/resources/locale/en.yml @@ -1,23 +1,20 @@ # the messages in this section can be customised for each rankup in rankups.yml. rankup: - requirements-not-met: "&cYou need {MONEY} money to rankup." + requirements-not-met: "&cYou need {{rank.requirement('money').total | simple}} money to rankup." no-rankup: "&eYou are at the highest rank." # set to an empty string, ie: success-public: "" # to hide that message. - success-public: "&a{PLAYER} &ehas ranked up to: &d{RANK}" - success-private: "&aYou have ranked up to: &d{RANK}" + success-public: "&a{{player}} &ehas ranked up to: &d{{next.rank}}" + success-private: "&aYou have ranked up to: &d{{next.rank}}" # used for the text confirmation confirmation: |- - &eAre you sure you want to rankup to &a{RANK}&e? + &eAre you sure you want to rankup to &a{{next.rank}}&e? &eType &c/rankup &eagain to confirm. - # used for the GUI confirmation - title: "Rankup to {RANK}" - must-prestige: "&cYou must prestige to /rankup further!" gui: rows: 1 - title: "Rankup to {RANK}" + title: "Rankup to {{next.rank}}" rankup: material: EMERALD_BLOCK # index can be separated by spaces to show in multiple groups @@ -26,7 +23,7 @@ rankup: index: 0-3 name: '&a&lConfirm' # lore is optional - lore: '&6Rankup to &b{RANK}' + lore: '&6Rankup to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -45,13 +42,13 @@ rankup: width: 7 complete: material: GREEN_STAINED_GLASS_PANE - name: "&aRank &7{RANK} &a(completed)" + name: "&aRank &7{{next.rank}} &a(completed)" current: material: ORANGE_STAINED_GLASS_PANE - name: "&dRankup to &7{RANK}" + name: "&dRankup to &7{{next.rank}}" incomplete: material: RED_STAINED_GLASS_PANE - name: "&cRank &7{RANK} &c(requires rankup)" + name: "&cRank &7{{next.rank}} &c(requires rankup)" fill: material: BLACK_STAINED_GLASS_PANE name: ' ' @@ -60,43 +57,43 @@ rankup: # you can (and probably should) you override these in rankups.yml # to show the specific requirements for each rank. # however if you are just using money or don't need to change the message per rank, you can use any combination of: - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. # here is an example of showing the requirements for just money: #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &efor &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &efor &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &efor &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &efor &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &efor &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &efor &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # an empty string disables the header/footer header: "" footer: "" # sent when a player tries to rankup when they are on cooldown cooldown: - singular: "&cYou must wait {SECONDS_LEFT} more second to rankup again." - plural: "&cYou must wait {SECONDS_LEFT} more seconds to rankup again." + singular: "&cYou must wait {{seconds_left}} more second to rankup again." + plural: "&cYou must wait {{seconds_left}} more seconds to rankup again." # prestige messages can also be customised prestige: - requirements-not-met: "&cYou need {MONEY} money to prestige." + requirements-not-met: "&cYou need {{rank.requirement('money').total | simple}} money to prestige." no-prestige: "&eYou are at the highest prestige." - success-public: "&a{PLAYER} &ehas prestiged to: &d{RANK}" - success-private: "&aYou have prestiged to: &d{RANK}" + success-public: "&a{{player}} &ehas prestiged to: &d{{next.rank}}" + success-private: "&aYou have prestiged to: &d{{next.rank}}" confirmation: |- - &eAre you sure you want to prestige to &a{RANK}&e? + &eAre you sure you want to prestige to &a{{next.rank}}&e? &eType &c/prestige &eagain to confirm. gui: - title: "Prestige to {RANK}" + title: "Prestige to {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConfirm' - lore: '&6Prestige to &b{RANK}' + lore: '&6Prestige to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -109,14 +106,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cYou must wait {SECONDS_LEFT} second to prestige again." - plural: "&cYou must wait {SECONDS_LEFT} more seconds to prestige again." + singular: "&cYou must wait {{seconds_left}} second to prestige again." + plural: "&cYou must wait {{seconds_left}} more seconds to prestige again." not-high-enough: "&cYou cannot prestige at your rank!" not-in-ladder: "&cSorry, but we could not find any rankups for the group(s) you are in. Use /ranks to list the rankups." diff --git a/src/main/resources/locale/es.yml b/src/main/resources/locale/es.yml index 14e2980..1894d50 100644 --- a/src/main/resources/locale/es.yml +++ b/src/main/resources/locale/es.yml @@ -4,20 +4,18 @@ rankup: no-rankup: "&eEstás en el último rango." # set to an empty string, ie: success-public: "" # to hide that message. - success-public: "&a{PLAYER} &eha subido de rango a: &d{RANK}" + success-public: "&a{{player}} &eha subido de rango a: &d{{next.rank}}" success-private: "" # used for the text confirmation confirmation: |- - &e¿Estás seguro de que quires subir de rango a &a{RANK}&e? + &e¿Estás seguro de que quires subir de rango a &a{{next.rank}}&e? &eEscribe /rankup para confirmar. - # used for the GUI confirmation - title: "Subir de rango a {RANK}" must-prestige: "&c¡Tienes que prestigiar para seguir subiendo de rango!" gui: rows: 1 - title: "Subir de rango a {RANK}" + title: "Subir de rango a {{next.rank}}" rankup: material: EMERALD_BLOCK # index can be separated by spaces to show in multiple groups @@ -26,7 +24,7 @@ rankup: index: 0-3 name: '&a&lConfirmar' # lore is optional - lore: '&6Subir de rango a {RANK}' + lore: '&6Subir de rango a {{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -45,56 +43,56 @@ rankup: width: 7 complete: material: GREEN_STAINED_GLASS_PANE - name: "&aRango &7{RANK} &a(completado)" + name: "&aRango &7{{next.rank}} &a(completado)" current: material: ORANGE_STAINED_GLASS_PANE - name: "&dSubir a &7{RANK}" + name: "&dSubir a &7{{next.rank}}" incomplete: material: RED_STAINED_GLASS_PANE - name: "&cRango &7{RANK} &c(requiere ascenso)" + name: "&cRango &7{{next.rank}} &c(requiere ascenso)" fill: material: BLACK_STAINED_GLASS_PANE name: ' ' # you can (and probably should) you override these in rankups.yml # to show the specific requirements for each rank. # however if you are just using money or don't need to change the message per rank, you can use any combination of: - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. # here is an example of showing the requirements for just money: #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &efor &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &efor &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &efor &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &efor &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &efor &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &efor &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # an empty string disables the header/footer header: "" footer: "" # sent when a player tries to rankup when they are on cooldown cooldown: - singular: "&cTienes que esperar {SECONDS_LEFT} segundo más para subir de rango otra vez." - plural: "&cTienes que esperar {SECONDS_LEFT} segundos más para subir de rango otra vez." + singular: "&cTienes que esperar {{seconds_left}} segundo más para subir de rango otra vez." + plural: "&cTienes que esperar {{seconds_left}} segundos más para subir de rango otra vez." # prestige messages can also be customised prestige: - requirements-not-met: "&cNecesitas {MONEY} más dinero para prestigiar." + requirements-not-met: "&cNecesitas {{rank.requirement('money').total | simple}} más dinero para prestigiar." no-prestige: "&eYa estás en el prestigio más alto." - success-public: "&a{PLAYER} &eha prestigiado a: &d{RANK}" + success-public: "&a{{player}} &eha prestigiado a: &d{{next.rank}}" success-private: "" confirmation: |- - &eEstás seguro de que quieres prestigiar a &a{RANK}&e? + &eEstás seguro de que quieres prestigiar a &a{{next.rank}}&e? &eEscribe &c/prestige &otra vez para confirmar. gui: - title: "Prestigiar a {RANK}" + title: "Prestigiar a {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConfirmar' - lore: '&6Prestigiar a &b{RANK}' + lore: '&6Prestigiar a &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -107,14 +105,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cTienes que esperar {SECONDS_LEFT} segundo más para prestigiar otra vez." - plural: "&cTienes que esperar {SECONDS_LEFT} segundos más para prestigiar otra vez." + singular: "&cTienes que esperar {{seconds_left}} segundo más para prestigiar otra vez." + plural: "&cTienes que esperar {{seconds_left}} segundos más para prestigiar otra vez." not-high-enough: "&c¡No puedes prestigiar a tu rango!" not-in-ladder: "&cPerdón, pero no hemos podido encontrar rangos en los grupos que perteneces. Usa /ranks para ver los rangos." diff --git a/src/main/resources/locale/fr.yml b/src/main/resources/locale/fr.yml index b00de9f..859f0ec 100644 --- a/src/main/resources/locale/fr.yml +++ b/src/main/resources/locale/fr.yml @@ -1,19 +1,19 @@ # the messages in this section can be customised for each rankup in rankups.yml. rankup: - requirements-not-met: "&cIl vous faut {MONEY} d'argent pour passer au rang suivant." + requirements-not-met: "&cIl vous faut {{rank.requirement('money').total | simple}} d'argent pour passer au rang suivant." no-rankup: "&eVous avez atteint le rang maximum." # set to an empty string, ie: success-public: "" # to hide that message. - success-public: "&a{PLAYER} &eest passé(e) au rang: &d{RANK}" - success-private: "&aVous êtes passé(e) au rang: &d{RANK}" + success-public: "&a{{player}} &eest passé(e) au rang: &d{{next.rank}}" + success-private: "&aVous êtes passé(e) au rang: &d{{next.rank}}" # used for the text confirmation confirmation: |- - &eÊtes-vous sûr(e) de vouloir passer au rang &a{RANK}&e? + &eÊtes-vous sûr(e) de vouloir passer au rang &a{{next.rank}}&e? &eTapez &c/rankup &eà nouveau pour confirmer. gui: rows: 1 - title: "Passer au rang {RANK}" + title: "Passer au rang {{next.rank}}" rankup: material: EMERALD_BLOCK # index can be separated by spaces to show in multiple groups @@ -22,7 +22,7 @@ rankup: index: 0-3 name: '&a&lConfirm' # lore is optional - lore: '&6Rankup to &b{RANK}' + lore: '&6Rankup to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -39,45 +39,45 @@ rankup: # you can (and probably should) you override these in rankups.yml # to show the specific requirements for each rank. # however if you are just using money or don't need to change the message per rank, you can use any combination of: - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} and {MONEY_NEEDED} are different from {AMOUNT money} and {AMOUNT_NEEDED money} in that they use a different format. # here is an example of showing the requirements for just money: #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &efor &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &efor &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &efor &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &efor &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &efor &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &efor &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # an empty string disables the header/footer header: "" footer: "" # sent when a player tries to rankup when they are on cooldown cooldown: - singular: "&cVous devez attendre encore {SECONDS_LEFT} seconde pour de nouveau passer un rang." - plural: "&cVous devez attendre encore {SECONDS_LEFT} secondes pour de nouveau passer un rang." + singular: "&cVous devez attendre encore {{seconds_left}} seconde pour de nouveau passer un rang." + plural: "&cVous devez attendre encore {{seconds_left}} secondes pour de nouveau passer un rang." # prestige messages can also be customised prestige: - requirements-not-met: "&cIl vous faut {MONEY} d'argent pour passer au rang suivant." + requirements-not-met: "&cIl vous faut {{rank.requirement('money').total | simple}} d'argent pour passer au rang suivant." no-prestige: "&eVous avez atteint le prestige maximum." - success-public: "&a{PLAYER} &eest passé(e) au prestige: &d{RANK}" - success-private: "&aVous êtes passé(e) au prestige: &d{RANK}" + success-public: "&a{{player}} &eest passé(e) au prestige: &d{{next.rank}}" + success-private: "&aVous êtes passé(e) au prestige: &d{{next.rank}}" confirmation: |- - &eÊtes-vous sûr(e) de vouloir passer au prestige &a{RANK}&e? + &eÊtes-vous sûr(e) de vouloir passer au prestige &a{{next.rank}}&e? &eTapez &c/prestige &eà nouveau pour confirmer. - title: "Passer au prestige {RANK}" + title: "Passer au prestige {{next.rank}}" gui: rows: 1 - title: "Prestige to {RANK}" + title: "Prestige to {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConfirm' - lore: '&6Prestige to &b{RANK}' + lore: '&6Prestige to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -90,14 +90,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cVous devez attendre encore {SECONDS_LEFT} seconde pour de nouveau passer un rang." - plural: "&cVous devez attendre encore {SECONDS_LEFT} secondes pour de nouveau passer un rang." + singular: "&cVous devez attendre encore {{seconds_left}} seconde pour de nouveau passer un rang." + plural: "&cVous devez attendre encore {{seconds_left}} secondes pour de nouveau passer un rang." not-high-enough: "&cVous ne pouvez pas passer de prestige à votre rang !" not-in-ladder: "&cDésolé, mais nous n'avons pas trouvé de rang pour le(s) groupe(s) dans lequel(s) vous êtes. Tapez /ranks pour voir la liste des rangs." diff --git a/src/main/resources/locale/it.yml b/src/main/resources/locale/it.yml index 97e8432..c78ec67 100644 --- a/src/main/resources/locale/it.yml +++ b/src/main/resources/locale/it.yml @@ -1,21 +1,19 @@ #traduzione italiana del locale per rankup rankup: - requirements-not-met: "&cHai bisogno di {MONEY} soldi per avanzare di rank." + requirements-not-met: "&cHai bisogno di {{rank.requirement('money').total | simple}} soldi per avanzare di rank." no-rankup: "&eSei al rank più alto." # imposta stringa vuota per nascondere il messaggio - success-public: "&a{PLAYER} &e\u00E8 avanzato di rank a: &d{RANK}" - success-private: "&aHai avanzato di rank a: &d{RANK}" + success-public: "&a{{player}} &e\u00E8 avanzato di rank a: &d{{next.rank}}" + success-private: "&aHai avanzato di rank a: &d{{next.rank}}" # conferma testuale confirmation: |- - &eSei sicuro di voler avanzare di rank a &a{RANK}&e? + &eSei sicuro di voler avanzare di rank a &a{{next.rank}}&e? &eScrivi &c/rankup &edi nuovo per confermare. - # conferma gui - title: "Avanzamento di rank a {RANK}" must-prestige: "&cDevi effettuare un prestige prima di avanzare di rank!" gui: - title: "Avanzamento di rank a {RANK}" + title: "Avanzamento di rank a {{next.rank}}" rankup: material: EMERALD_BLOCK # l'indice può essere separato da spazi per mostrarlo in più gruppi @@ -24,7 +22,7 @@ rankup: index: 0-3 name: '&a&lConferma' # lore opzionale - lore: '&6Avanzamento a &b{RANK}' + lore: '&6Avanzamento a &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -43,13 +41,13 @@ rankup: width: 7 complete: material: GREEN_STAINED_GLASS_PANE - name: "&aRank &7{RANK} &a(completed)" + name: "&aRank &7{{next.rank}} &a(completed)" current: material: ORANGE_STAINED_GLASS_PANE - name: "&dRankup to &7{RANK}" + name: "&dRankup to &7{{next.rank}}" incomplete: material: RED_STAINED_GLASS_PANE - name: "&cRank &7{RANK} &c(requires rankup)" + name: "&cRank &7{{next.rank}} &c(requires rankup)" fill: material: BLACK_STAINED_GLASS_PANE name: ' ' @@ -57,43 +55,43 @@ rankup: # potresti e dovresti configurare questi in rankup.yml # per visualizzare i requisiti di ogni rank # ma se stai usando solo i soldi e non ti serve modificare il mesaggio puoi usapre questi - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} e {MONEY_NEEDED} sono diversi da {AMOUNT money} e {AMOUNT_NEEDED money}, usano un formato diverso + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} e {MONEY_NEEDED} sono diversi da {AMOUNT money} e {AMOUNT_NEEDED money}, usano un formato diverso # ESEMPIO: #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &efor &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &efor &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &efor &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &efor &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &efor &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &efor &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # stringa vuota per disattivare header: "" footer: "" # messaggi cooldown cooldown: - singular: "&cDevi aspettare ancora {SECONDS_LEFT} secondo per avanzare di rank." - plural: "&cDevi aspettare ancora {SECONDS_LEFT} secondi per avanzare di rank." + singular: "&cDevi aspettare ancora {{seconds_left}} secondo per avanzare di rank." + plural: "&cDevi aspettare ancora {{seconds_left}} secondi per avanzare di rank." # messaggi prestige prestige: - requirements-not-met: "&cHai bisogno di {MONEY} soldi per effettuare un prestige." + requirements-not-met: "&cHai bisogno di {{rank.requirement('money').total | simple}} soldi per effettuare un prestige." no-prestige: "&eSei al prestige più alto." - success-public: "&a{PLAYER} &eha effettuato un prestige a: &d{RANK}" - success-private: "&aHai effettuato un prestige a: &d{RANK}" + success-public: "&a{{player}} &eha effettuato un prestige a: &d{{next.rank}}" + success-private: "&aHai effettuato un prestige a: &d{{next.rank}}" confirmation: |- - &eSei sicuro di voler effettuare un prestige a &a{RANK}&e? + &eSei sicuro di voler effettuare un prestige a &a{{next.rank}}&e? &eScrivi &c/prestige &edi nuovo per confermare. gui: - title: "Prestige a {RANK}" + title: "Prestige a {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConferma' - lore: '&6Prestige a &b{RANK}' + lore: '&6Prestige a &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -104,14 +102,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cDevi aspettare {SECONDS_LEFT} secondo per effettuare un altro prestige." - plural: "&cDevi aspettare {SECONDS_LEFT} secondi per effettuare un altro prestige." + singular: "&cDevi aspettare {{seconds_left}} secondo per effettuare un altro prestige." + plural: "&cDevi aspettare {{seconds_left}} secondi per effettuare un altro prestige." not-high-enough: "&cNon puoi effettuare un prestige al tuo rank!" not-in-ladder: "&cNon riusciamo a trovare nessun avanzamento di rank per il tuo gruppo. Scrivi /ranks per ottenere una lista degli avanzamenti disponibili." diff --git a/src/main/resources/locale/pt_br.yml b/src/main/resources/locale/pt_br.yml index 3a3b50a..8899c5e 100644 --- a/src/main/resources/locale/pt_br.yml +++ b/src/main/resources/locale/pt_br.yml @@ -1,21 +1,21 @@ # As mensagens nessa sessão podem ser customizadas para cada rankup em rankups.yml. rankup: - requirements-not-met: "&cVocê {MONEY} para poder dar subir de rank." + requirements-not-met: "&cVocê {{rank.requirement('money').total | simple}} para poder dar subir de rank." no-rankup: "&eVocê já está no maior rank." # coloque como uma String vazia, ex: success-public: "" # para ocultar a mensagem. - success-public: "&a{PLAYER} &eacaba de subir para: &d{RANK}" - success-private: "&aVocê subiu para: &d{RANK}" + success-public: "&a{{player}} &eacaba de subir para: &d{{next.rank}}" + success-private: "&aVocê subiu para: &d{{next.rank}}" # Utilizado para a confirmação via mensagem. confirmation: |- - &eVocê tem certeza que deseja subir para &a{RANK}&e? + &eVocê tem certeza que deseja subir para &a{{next.rank}}&e? &eDigite &c/rankup &enovamente para confirmar. must-prestige: "&cVocê deve subir de prestígio para dar /rankup a frente!" gui: rows: 1 - title: "Rankup to {RANK}" + title: "Rankup to {{next.rank}}" rankup: material: EMERALD_BLOCK # index can be separated by spaces to show in multiple groups @@ -24,7 +24,7 @@ rankup: index: 0-3 name: '&a&lConfirm' # lore is optional - lore: '&6Rankup to &b{RANK}' + lore: '&6Rankup to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -39,48 +39,48 @@ rankup: # Você pode (e deveria) substituir isto em rankups.yml # para mostrar os requerimentos específicos para cada rank. # contudo, se você está apenas usando dinheiro ou não precisa mudar as mensagens por rank, você pode usar qualquer combinação de: - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} e {MONEY_NEEDED} são diferentes de {AMOUNT money} e {AMOUNT_NEEDED money} pois eles usam diferentes formatos. + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} e {MONEY_NEEDED} são diferentes de {AMOUNT money} e {AMOUNT_NEEDED money} pois eles usam diferentes formatos. # here is an example of showing the requirements for just money: # Segue um exemplo de como mostrar um requerimento para apenas dinheiro. #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &efor &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &efor &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &efor &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &efor &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &efor &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &efor &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # Uma string vázia desativa o cabeçalho/rodapé header: "" footer: "" # sent when a player tries to rankup when they are on cooldown. # Enviado quando um jogador tenta dar rankup enquanto ele está em um cooldown (tempo de espera entre comandos, freeze). cooldown: - singular: "&cVocê precisa esperar {SECONDS_LEFT} segundo para dar rankup novamente." - plural: "&cVocê precisa {SECONDS_LEFT} segundos para dar rankup novamente." + singular: "&cVocê precisa esperar {{seconds_left}} segundo para dar rankup novamente." + plural: "&cVocê precisa {{seconds_left}} segundos para dar rankup novamente." # prestige messages can also be customised # Mensagens de prestígio também podem ser customizadas prestige: - requirements-not-met: "&cVocê precisa {MONEY} para dar prestigiar." + requirements-not-met: "&cVocê precisa {{rank.requirement('money').total | simple}} para dar prestigiar." no-prestige: "&eVocê está no maior prestígio." - success-public: "&a{PLAYER} &esubiu de prestígio para: &d{RANK}" - success-private: "&aVocê subiu de prestígio para: &d{RANK}" + success-public: "&a{{player}} &esubiu de prestígio para: &d{{next.rank}}" + success-private: "&aVocê subiu de prestígio para: &d{{next.rank}}" confirmation: |- - &eVocê tem certeza que deseja subir de prestígio para &a{RANK}&e? + &eVocê tem certeza que deseja subir de prestígio para &a{{next.rank}}&e? &eDigite &c/prestige &enovamente para confimar. - title: "Subiu de prestígio para {RANK}" + title: "Subiu de prestígio para {{next.rank}}" gui: rows: 1 - title: "Prestige to {RANK}" + title: "Prestige to {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConfirm' - lore: '&6Prestige to &b{RANK}' + lore: '&6Prestige to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -93,14 +93,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cVocê deve esperar {SECONDS_LEFT} segundo para subir de prestígio novamente." - plural: "&cVocê deve esperar {SECONDS_LEFT} segundos para subir de prestígio novamente." + singular: "&cVocê deve esperar {{seconds_left}} segundo para subir de prestígio novamente." + plural: "&cVocê deve esperar {{seconds_left}} segundos para subir de prestígio novamente." not-high-enough: "&cVocê não pode subir de prestígio nesse rank!" not-in-ladder: "&cDesculpa, não conseguimos achar nenhum rank para você subir." diff --git a/src/main/resources/locale/ru.yml b/src/main/resources/locale/ru.yml index e050121..d980d16 100644 --- a/src/main/resources/locale/ru.yml +++ b/src/main/resources/locale/ru.yml @@ -1,18 +1,18 @@ # Сообщения в этой секции могут быть изменены для каждого повышения уровня в rankups.yml rankup: - requirements-not-met: "&cВам нужно ещё {MONEY} денег для повышения уровня." + requirements-not-met: "&cВам нужно ещё {{rank.requirement('money').total | simple}} денег для повышения уровня." no-rankup: "&eУ Вас уже самый высокий ранг." # Оставьте это поле пустым, чтобы скрыть сообщение (success-public: '') - success-public: "&eРанг игрока &a{PLAYER} &eбыл повышен до: &d{RANK}" - success-private: "&aВаш ранг повысился до: &d{RANK}" + success-public: "&eРанг игрока &a{{player}} &eбыл повышен до: &d{{next.rank}}" + success-private: "&aВаш ранг повысился до: &d{{next.rank}}" # Используется как текст подтверждения confirmation: |- - &eВы уверены, что хотите ранг до &a{RANK}&e? + &eВы уверены, что хотите ранг до &a{{next.rank}}&e? &eВведите &c/rankup &eещё раз, чтобы подтвердить. gui: rows: 1 - title: "Повысить до {RANK}" + title: "Повысить до {{next.rank}}" rankup: material: EMERALD_BLOCK # index can be separated by spaces to show in multiple groups @@ -21,7 +21,7 @@ rankup: index: 0-3 name: '&a&lConfirm' # lore is optional - lore: '&6Rankup to &b{RANK}' + lore: '&6Rankup to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -37,47 +37,47 @@ rankup: # Вы можете (вам стоит ;D) переписать это в rankups.yml, чтобы показать специфичные требования для каждого ранга. # Тем не менее, если Вы просто используете деньги или не нуждаетесь в смене сообщений для кажого ранга - Вы - # можете использовать комбинации из: {MONEY} {MONEY_NEEDED} {PERCENT_DONE <требование>} {PERCENT_LEFT <требование>} - # {AMOUNT <требование>} {AMOUNT_NEDDED <требование>}. "{MONEY}" и "{MONEY_NEEDED}" отличаются от + # можете использовать комбинации из: {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE <требование>} {PERCENT_LEFT <требование>} + # {AMOUNT <требование>} {AMOUNT_NEDDED <требование>}. "{{rank.requirement('money').total | simple}}" и "{MONEY_NEEDED}" отличаются от # {AMOUNT сумма} {AMOUNT_NEDDED сумма} тем, что они используют разный формат. # Вот пример показа требований только для денег # P.S. \xbb - "»" в Unicode. #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &eза &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &eза &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &eза &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &eза &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &eза &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &eза &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # Пустая строка выключает заголовок/нижнюю часть header: '' footer: '' # Отправляется игроку, который попытался повысить уровень, когда ещё не прошёл кулдаун (откат/перезарядка) cooldown: - singular: "&cПожалуйста, подождите {SECONDS_LEFT} сек., чтобы повысить ранг снова." - plural: "&cПожалуйста, подождите {SECONDS_LEFT} сек., чтобы повысить ранг снова." + singular: "&cПожалуйста, подождите {{seconds_left}} сек., чтобы повысить ранг снова." + plural: "&cПожалуйста, подождите {{seconds_left}} сек., чтобы повысить ранг снова." # Сообщения престижа тоже могут быть изменены prestige: - requirements-not-met: "&cВам нужно {MONEY} денг для повышения престижа." + requirements-not-met: "&cВам нужно {{rank.requirement('money').total | simple}} денг для повышения престижа." no-prestige: "&eУ Вас уже самый высокий уровень престижа." - success-public: "Престиж игрока &a{PLAYER} &eповышен в: &d{RANK}" - success-private: "&aВаш престиж повышен в: &d{RANK}" + success-public: "Престиж игрока &a{{player}} &eповышен в: &d{{next.rank}}" + success-private: "&aВаш престиж повышен в: &d{{next.rank}}" confirmation: |- - &eВы уверены, что хотите престиж в &a{RANK}&e? + &eВы уверены, что хотите престиж в &a{{next.rank}}&e? &eВведите &c/prestige &eснова для подтверждения. - title: "Повысить престиж в {RANK}" + title: "Повысить престиж в {{next.rank}}" gui: rows: 1 - title: "Prestige to {RANK}" + title: "Prestige to {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&lConfirm' - lore: '&6Prestige to &b{RANK}' + lore: '&6Prestige to &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -90,14 +90,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&cПожалуйста, подождите {SECONDS_LEFT} сек., чтобы повысить ранг снова." - plural: "&cПожалуйста, подождите {SECONDS_LEFT} сек., чтобы повысить ранг снова." + singular: "&cПожалуйста, подождите {{seconds_left}} сек., чтобы повысить ранг снова." + plural: "&cПожалуйста, подождите {{seconds_left}} сек., чтобы повысить ранг снова." not-high-enough: "&cВы не можете поднять уровень престижа в этом ранге" not-in-ladder: "&cПростите, но мне не можем найти какие-нибудь повышения для Вашей группы." diff --git a/src/main/resources/locale/zh_cn.yml b/src/main/resources/locale/zh_cn.yml index ff02dfa..4947183 100644 --- a/src/main/resources/locale/zh_cn.yml +++ b/src/main/resources/locale/zh_cn.yml @@ -1,24 +1,22 @@ # 这部分的信息能在 rankups.yml 对不同的段位进行自定义。 rankup: - requirements-not-met: "&c您需要 {MONEY} 游戏币才能晋级。" + requirements-not-met: "&c您需要 {{rank.requirement('money').total | simple}} 游戏币才能晋级。" no-rankup: "&e您目前已处于段位的顶端。" # 想设置字符串为空? # 一个例子: success-public: "" # 这将隐藏那条信息。 - success-public: "&a{PLAYER} &e已经晋升至新的段位: &d{RANK}" - success-private: "&a您成功晋升到新的段位: &d{RANK}" + success-public: "&a{{player}} &e已经晋升至新的段位: &d{{next.rank}}" + success-private: "&a您成功晋升到新的段位: &d{{next.rank}}" # 用于二次确认的文本信息 confirmation: |- - &e您确定您要晋级至 &a{RANK}&e? + &e您确定您要晋级至 &a{{next.rank}}&e? &e再次输入 &c/rankup &e以确认操作。 - # 用于二次确认的 GUI 信息 - title: "晋级至 {RANK}" must-prestige: "&c您必须再次输入 /rankup !" gui: rows: 1 - title: "晋级至 {RANK}" + title: "晋级至 {{next.rank}}" rankup: material: EMERALD_BLOCK # 可以用空格分隔序号以显示在多个槽位组中 @@ -27,7 +25,7 @@ rankup: index: 0-3 name: '&a&l确认' # lore 可有可无 - lore: '&6晋级至 &b{RANK}' + lore: '&6晋级至 &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -46,13 +44,13 @@ rankup: width: 7 complete: material: GREEN_STAINED_GLASS_PANE - name: "&a段位等级 &7{RANK} &a(已达成)" + name: "&a段位等级 &7{{next.rank}} &a(已达成)" current: material: ORANGE_STAINED_GLASS_PANE - name: "&d晋升段位等级至 &7{RANK}" + name: "&d晋升段位等级至 &7{{next.rank}}" incomplete: material: RED_STAINED_GLASS_PANE - name: "&c段位等级 &7{RANK} &c(需要晋升)" + name: "&c段位等级 &7{{next.rank}} &c(需要晋升)" fill: material: BLACK_STAINED_GLASS_PANE name: ' ' @@ -61,42 +59,42 @@ rankup: # 您可以(也可能应该)在 rankups.yml # 显示每个等级的具体要求。 # 但是,如果您只想使用游戏币作为晋升需求或不需要更改每个级别的消息,则可以使用以下任意组合: - # {MONEY} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } - # {MONEY} 和 {MONEY_NEEDED} 相较于 {AMOUNT money} 和 {AMOUNT_NEEDED money} 在使用的格式上不尽相同。 + # {{rank.requirement('money').total | simple}} {MONEY_NEEDED} {PERCENT_DONE } {PERCENT_LEFT } {AMOUNT } {AMOUNT_NEEDED } + # {{rank.requirement('money').total | simple}} 和 {MONEY_NEEDED} 相较于 {AMOUNT money} 和 {AMOUNT_NEEDED money} 在使用的格式上不尽相同。 # 这里有一个只使用游戏币作为晋升条件的示例: #list: - # complete: "&7{OLD_RANK} &8\xbb &7{RANK} &e花费 &7${MONEY}" - # current: "&c{OLD_RANK} &e\xbb &c{RANK} &e花费 &a${MONEY} &e{PERCENT_DONE money}%" - # incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &e花费 &a${MONEY}" + # complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &e花费 &7${{rank.requirement('money').total | simple}}" + # current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &e花费 &a${{rank.requirement('money').total | simple}} &e{PERCENT_DONE money}%" + # incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &e花费 &a${{rank.requirement('money').total | simple}}" list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" # 一个空字符串可以关闭 header(页眉)/footer(页脚) header: "" footer: "" # 这些信息将在玩家处于晋升冷却期间尝试升级后发送 cooldown: - singular: "&c您必须等待 {SECONDS_LEFT} 秒才能进行晋升段位等级操作。" - plural: "&c您必须等待 {SECONDS_LEFT} 秒才能进行晋升段位等级操作。" + singular: "&c您必须等待 {{seconds_left}} 秒才能进行晋升段位等级操作。" + plural: "&c您必须等待 {{seconds_left}} 秒才能进行晋升段位等级操作。" # 声望信息也可以定制 prestige: - requirements-not-met: "&c您需要 {MONEY} 游戏币才能进行声望等级升级。" + requirements-not-met: "&c您需要 {{rank.requirement('money').total | simple}} 游戏币才能进行声望等级升级。" no-prestige: "&e您目前已经处在最高的声望等级了。" - success-public: "&a{PLAYER} &e已经晋升至: &d{RANK}" - success-private: "&a您成功晋升声望至: &d{RANK}" + success-public: "&a{{player}} &e已经晋升至: &d{{next.rank}}" + success-private: "&a您成功晋升声望至: &d{{next.rank}}" confirmation: |- - &e您确定要晋升声望至 &a{RANK}&e? + &e您确定要晋升声望至 &a{{next.rank}}&e? &e再次输入 &c/prestige &e确认操作。 gui: - title: "声望晋升至 {RANK}" + title: "声望晋升至 {{next.rank}}" rankup: material: GOLD_BLOCK index: 0-3 name: '&a&l确认' - lore: '&6声望晋升至 &b{RANK}' + lore: '&6声望晋升至 &b{{next.rank}}' cancel: material: REDSTONE_BLOCK index: 5-8 @@ -109,14 +107,14 @@ prestige: material: BLACK_STAINED_GLASS_PANE list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK}" - current: "&c{OLD_RANK} &e\xbb &c{RANK}" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK}" + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}}" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}}" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}}" header: "" footer: "" cooldown: - singular: "&c您必须等待 {SECONDS_LEFT} 秒才能再次晋升声望等级。" - plural: "&c您必须等待 {SECONDS_LEFT} 秒才能再次晋升声望等级。" + singular: "&c您必须等待 {{seconds_left}} 秒才能再次晋升声望等级。" + plural: "&c您必须等待 {{seconds_left}} 秒才能再次晋升声望等级。" not-high-enough: "&c您无法在您当前等级上进行声望晋升!" not-in-ladder: "&c抱歉,我们找不到您所在小组的任何段位等级。使用 /ranks 列出所有段位等级。" diff --git a/src/main/resources/rankups.yml b/src/main/resources/rankups.yml index a2ba234..567c59f 100644 --- a/src/main/resources/rankups.yml +++ b/src/main/resources/rankups.yml @@ -22,7 +22,7 @@ Aexample: # nb: groups are automatically changed with vault #commands: # this will run when a player ranks up from A to B. - #- 'say {PLAYER} well done for ranking up from {OLD_RANK} to {RANK}!' + #- 'say {{player}} well done for ranking up from {{rank.rank}} to {{next.rank}}!' Bexample: rank: 'B' next: 'C' @@ -39,6 +39,6 @@ Cexample: rankup: requirements-not-met: '&cYou need 5000 money and 2 levels of XP to rankup to D.' list: - complete: "&7{OLD_RANK} &8\xbb &7{RANK} &e(5000 money, 2 XP levels)" - current: "&c{OLD_RANK} &e\xbb &c{RANK} &e(5000 money, 2 XP levels)" - incomplete: "&r{OLD_RANK} &e\xbb &r{RANK} &e(5000 money, 2 XP levels)" \ No newline at end of file + complete: "&7{{rank.rank}} &8\xbb &7{{next.rank}} &e(5000 money, 2 XP levels)" + current: "&c{{rank.rank}} &e\xbb &c{{next.rank}} &e(5000 money, 2 XP levels)" + incomplete: "&r{{rank.rank}} &e\xbb &r{{next.rank}} &e(5000 money, 2 XP levels)" \ No newline at end of file diff --git a/src/test/java/sh/okx/rankup/RankupBasicsTest.java b/src/test/java/sh/okx/rankup/RankupBasicsTest.java new file mode 100644 index 0000000..a2dbe6e --- /dev/null +++ b/src/test/java/sh/okx/rankup/RankupBasicsTest.java @@ -0,0 +1,67 @@ +package sh.okx.rankup; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import org.junit.Test; +import sh.okx.rankup.messages.Message; +import sh.okx.rankup.ranks.Rank; +import sh.okx.rankup.ranks.RankElement; + +public class RankupBasicsTest extends RankupTest { + @Test + public void testAutoRankup() { + PlayerMock player = server.addPlayer(); + + // requirement of $1000 + plugin.getEconomy().setPlayer(player, 1000); + // give them group A + groupProvider.addGroup(player.getUniqueId(), "A"); + // give the permission to auto rankup + player.addAttachment(plugin, "rankup.auto", true); + + plugin.autoRankup.run(); + assertTrue(groupProvider.inGroup(player.getUniqueId(), "B")); + assertEquals(0, plugin.getEconomy().getBalance(player), 0); + } + + @Test + public void testNotInLadder() { + PlayerMock player = server.addPlayer(); + + plugin.getHelper().rankup(player); + + player.assertSaid(plugin.getMessage(Message.NOT_IN_LADDER).replacePlayer(player).toString()); + player.assertNoMoreSaid(); + } + + @Test + public void testLastRank() { + PlayerMock player = server.addPlayer(); + + groupProvider.addGroup(player.getUniqueId(), "D"); + + plugin.getHelper().rankup(player); + + player.assertSaid(plugin.getMessage(Message.NO_RANKUP).replacePlayer(player) + .replaceRank(plugin.getRankups().getTree().last().getRank()).toString()); + player.assertNoMoreSaid(); + } + + @Test + public void testMoneyRequirement() { + PlayerMock player = server.addPlayer(); + + plugin.getEconomy().setPlayer(player, 500); + + groupProvider.addGroup(player.getUniqueId(), "A"); + plugin.getHelper().rankup(player); + + RankElement element = plugin.getRankups().getTree().getFirst(); + Rank rank = element.getRank(); + + player.assertSaid(plugin.getMessage(rank, Message.REQUIREMENTS_NOT_MET).replacePlayer(player).replaceOldRank(rank).replaceRank(element.getNext().getRank()).toString(player)); + player.assertNoMoreSaid(); + } +} diff --git a/src/test/java/sh/okx/rankup/RankupTest.java b/src/test/java/sh/okx/rankup/RankupTest.java index 012b1f7..dcd68f4 100644 --- a/src/test/java/sh/okx/rankup/RankupTest.java +++ b/src/test/java/sh/okx/rankup/RankupTest.java @@ -1,101 +1,85 @@ package sh.okx.rankup; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import be.seeseemelk.mockbukkit.MockBukkit; import be.seeseemelk.mockbukkit.ServerMock; -import be.seeseemelk.mockbukkit.entity.PlayerMock; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import org.junit.After; import org.junit.Before; -import org.junit.Test; import sh.okx.rankup.economy.TestEconomyProvider; import sh.okx.rankup.hook.GroupProvider; import sh.okx.rankup.hook.TestGroupProvider; import sh.okx.rankup.hook.TestPermissionManager; -import sh.okx.rankup.messages.Message; -import sh.okx.rankup.messages.Variable; -import sh.okx.rankup.ranks.Rank; -import sh.okx.rankup.ranks.RankElement; -public class RankupTest { +public abstract class RankupTest { + private final File testResourceFolder; + + public RankupTest() { + this("default"); + } + + public RankupTest(String testResourceFolder) { + URL resource = this.getClass().getResource("/" + testResourceFolder); + if (resource != null) { + this.testResourceFolder = new File(resource.getPath()); + } else { + this.testResourceFolder = null; + } + } + protected GroupProvider groupProvider; protected ServerMock server; protected RankupPlugin plugin; @Before public void setup() { - System.setProperty("TEST", "true"); + System.setProperty("RANKUP_TEST", "true"); try { groupProvider = new TestGroupProvider(); server = MockBukkit.mock(); - plugin = MockBukkit.load(RankupPlugin.class, new TestPermissionManager(groupProvider), new TestEconomyProvider()); + plugin = (RankupPlugin) server.getPluginManager() + .loadPlugin(RankupPlugin.class, new Object[]{ + new TestPermissionManager(groupProvider), + new TestEconomyProvider() + }); + + if (this.testResourceFolder != null) { + Path testPath = this.testResourceFolder.toPath(); + Path pluginPath = plugin.getDataFolder().toPath(); + Files.walkFileTree(testPath, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Path out = pluginPath.resolve(testPath.relativize(file)); + System.out.println("Copy " + file + " to " + out); + out.getParent().toFile().mkdirs(); + Files.copy(file, out); + return super.visitFile(file, attrs); + } + }); + } + + server.getPluginManager().enablePlugin(plugin); + // let rankup finish setting up server.getScheduler().performTicks(1); + } catch (Exception e) { e.printStackTrace(); } } - @Test - public void testAutoRankup() { - PlayerMock player = server.addPlayer(); - - // requirement of $1000 - plugin.getEconomy().setPlayer(player, 1000); - // give them group A - groupProvider.addGroup(player.getUniqueId(), "A"); - // give the permission to auto rankup - player.addAttachment(plugin, "rankup.auto", true); - - plugin.autoRankup.run(); - assertTrue(groupProvider.inGroup(player.getUniqueId(), "B")); - assertEquals(0, plugin.getEconomy().getBalance(player), 0); - } - - @Test - public void testNotInLadder() { - PlayerMock player = server.addPlayer(); - - plugin.getHelper().rankup(player); - - player.assertSaid(plugin.getMessage(Message.NOT_IN_LADDER).replace(Variable.PLAYER, player.getName()).toString()); - player.assertNoMoreSaid(); - } - - @Test - public void testLastRank() { - PlayerMock player = server.addPlayer(); - - groupProvider.addGroup(player.getUniqueId(), "D"); - - plugin.getHelper().rankup(player); - - player.assertSaid(plugin.getMessage(Message.NO_RANKUP).replaceRanks(player, plugin.getRankups().getTree().last().getRank()).toString()); - player.assertNoMoreSaid(); - } - - @Test - public void testMoneyRequirement() { - PlayerMock player = server.addPlayer(); - - plugin.getEconomy().setPlayer(player, 500); - - groupProvider.addGroup(player.getUniqueId(), "A"); - plugin.getHelper().rankup(player); - - RankElement element = plugin.getRankups().getTree().getFirst(); - Rank rank = element.getRank(); - - player.assertSaid(plugin.replaceMoneyRequirements(plugin.getMessage(rank, Message.REQUIREMENTS_NOT_MET).replaceRanks(player, rank, element.getNext().getRank()), player, rank).toString()); - player.assertNoMoreSaid(); - } - @After public void tearDown() { MockBukkit.unmock(); - System.clearProperty("TEST"); + System.clearProperty("RANKUP_TEST"); } } diff --git a/src/test/java/sh/okx/rankup/legacy/LegacyPlaceholderTest.java b/src/test/java/sh/okx/rankup/legacy/LegacyPlaceholderTest.java new file mode 100644 index 0000000..a27f717 --- /dev/null +++ b/src/test/java/sh/okx/rankup/legacy/LegacyPlaceholderTest.java @@ -0,0 +1,24 @@ +package sh.okx.rankup.legacy; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import org.junit.Test; +import sh.okx.rankup.RankupTest; + +public class LegacyPlaceholderTest extends RankupTest { + public LegacyPlaceholderTest() { + super("legacy"); + } + + @Test + public void testLegacy() { + PlayerMock player = server.addPlayer("testPlayer"); + + plugin.getEconomy().setPlayer(player, 100); + player.setLevel(1); + + groupProvider.addGroup(player.getUniqueId(), "A"); + plugin.getHelper().rankup(player); + + player.assertSaid("testPlayer A B A-display last rank 1,000 900 4 1 3 25 75"); + } +} diff --git a/src/test/java/sh/okx/rankup/messages/MessageBuilderTest.java b/src/test/java/sh/okx/rankup/messages/MessageBuilderTest.java index f48d205..ee82f80 100644 --- a/src/test/java/sh/okx/rankup/messages/MessageBuilderTest.java +++ b/src/test/java/sh/okx/rankup/messages/MessageBuilderTest.java @@ -8,6 +8,6 @@ import static org.junit.Assert.assertThat; public class MessageBuilderTest { @Test public void testFailIfEmpty() { - assertThat(new MessageBuilder("").failIfEmpty(), instanceOf(NullMessageBuilder.class)); + assertThat(new StringMessageBuilder("").failIfEmpty(), instanceOf(NullMessageBuilder.class)); } } \ No newline at end of file diff --git a/src/test/java/sh/okx/rankup/messages/RankupPlaceholderTest.java b/src/test/java/sh/okx/rankup/messages/RankupPlaceholderTest.java new file mode 100644 index 0000000..66a49f5 --- /dev/null +++ b/src/test/java/sh/okx/rankup/messages/RankupPlaceholderTest.java @@ -0,0 +1,24 @@ +package sh.okx.rankup.messages; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import org.junit.Test; +import sh.okx.rankup.RankupTest; + +public class RankupPlaceholderTest extends RankupTest { + @Test + public void testSuccessPublicIsSame() { + PlayerMock player = server.addPlayer(); + PlayerMock receiver = server.addPlayer(); + + plugin.getEconomy().setPlayer(player, 1000); + + groupProvider.addGroup(player.getUniqueId(), "A"); + plugin.getHelper().rankup(player); + + // success-public message must be the same for both players + player.assertSaid(receiver.nextMessage()); + + // receiver does not receive success-private + receiver.assertNoMoreSaid(); + } +} diff --git a/src/test/java/sh/okx/rankup/pebble/PebbleTest.java b/src/test/java/sh/okx/rankup/pebble/PebbleTest.java new file mode 100644 index 0000000..add5a02 --- /dev/null +++ b/src/test/java/sh/okx/rankup/pebble/PebbleTest.java @@ -0,0 +1,26 @@ +package sh.okx.rankup.pebble; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import sh.okx.rankup.text.pebble.PebbleTextProcessor; + +public class PebbleTest { + @Test + public void testIndex() { + Map ctx = new HashMap<>(); + ctx.put("one", "2"); + List list = new ArrayList<>(); + list.add("L0"); + list.add("L1"); + list.add("L2"); + list.add("L3"); + ctx.put("list", list); + PebbleTextProcessor processor = new PebbleTextProcessor(ctx, null); + assertEquals("L2", processor.process("{{ list[one] }}")); + } +} diff --git a/src/test/resources/legacy/rankups.yml b/src/test/resources/legacy/rankups.yml new file mode 100644 index 0000000..46d7bfd --- /dev/null +++ b/src/test/resources/legacy/rankups.yml @@ -0,0 +1,10 @@ +A: + rank: 'A' + next: 'B' + display-name: 'A-display' + requirements: + - 'money 1000' + - 'xp-level 4' + rankup: + # Test legacy placeholders + requirements-not-met: '{PLAYER} {OLD_RANK} {RANK} {OLD_RANK_NAME} {RANK_NAME} {MONEY} {MONEY_NEEDED} {AMOUNT xp-level} {AMOUNT_DONE xp-level} {AMOUNT_NEEDED xp-level} {PERCENT_DONE xp-level} {PERCENT_LEFT xp-level}' \ No newline at end of file