├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── build.gradle ├── crowdin.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs └── nuvotifier-2.7.3.jar ├── renovate.json ├── settings.gradle ├── src └── main │ ├── java │ └── me │ │ └── clip │ │ └── voteparty │ │ └── plugin │ │ └── VotePartyPlugin.java │ ├── kotlin │ └── me │ │ └── clip │ │ └── voteparty │ │ ├── VoteParty.kt │ │ ├── base │ │ ├── Addon.kt │ │ └── State.kt │ │ ├── bungee │ │ └── NuVotifierBungeeHandler.kt │ │ ├── cmds │ │ └── CommandVoteParty.kt │ │ ├── conf │ │ ├── VoteDataConfiguration.kt │ │ ├── VotePartyConfiguration.kt │ │ ├── mapper │ │ │ └── SingleValueToCollectionMapper.kt │ │ ├── migrations │ │ │ └── VoteMigrationService.kt │ │ ├── objects │ │ │ ├── Command.kt │ │ │ ├── Commands.kt │ │ │ ├── Counter.kt │ │ │ ├── CumulativeVoteCommands.kt │ │ │ ├── CumulativeVoteRewards.kt │ │ │ ├── CumulativeVoting.kt │ │ │ ├── Effects.kt │ │ │ ├── NuVotifier.kt │ │ │ ├── PermCommands.kt │ │ │ ├── PermRewards.kt │ │ │ ├── RewardsPerEvent.kt │ │ │ ├── VotesiteCommands.kt │ │ │ └── VotesiteRewards.kt │ │ └── sections │ │ │ ├── CrateSettings.kt │ │ │ ├── EffectsSettings.kt │ │ │ ├── HookSettings.kt │ │ │ ├── PartySettings.kt │ │ │ ├── PluginSettings.kt │ │ │ ├── VoteData.kt │ │ │ └── VoteSettings.kt │ │ ├── data │ │ ├── base │ │ │ ├── DatabaseVotePlayer.kt │ │ │ ├── PartiesCache.kt │ │ │ └── VotedForPartyCache.kt │ │ └── impl │ │ │ ├── DatabaseVotePlayerGson.kt │ │ │ ├── PartiesCacheGson.kt │ │ │ └── VotedForPartyCacheGson.kt │ │ ├── events │ │ ├── PartyEndEvent.kt │ │ ├── PartyStartEvent.kt │ │ ├── PrePartyEvent.kt │ │ └── VoteReceivedEvent.kt │ │ ├── exte │ │ ├── const.kt │ │ ├── funcs.kt │ │ └── texts.kt │ │ ├── handler │ │ ├── LeaderboardHandler.kt │ │ ├── PartyHandler.kt │ │ └── VotesHandler.kt │ │ ├── leaderboard │ │ ├── Leaderboard.kt │ │ ├── LeaderboardType.kt │ │ └── LeaderboardUser.kt │ │ ├── listener │ │ ├── CrateListener.kt │ │ ├── HooksListenerNuVotifier.kt │ │ ├── VotesListener.kt │ │ └── base │ │ │ └── VotePartyListener.kt │ │ ├── messages │ │ └── Messages.kt │ │ ├── placeholders │ │ └── VotePartyPlaceholders.kt │ │ ├── user │ │ ├── User.kt │ │ └── UsersHandler.kt │ │ └── util │ │ ├── JarFileWalker.kt │ │ └── UpdateChecker.kt │ └── resources │ ├── config.yml │ ├── languages │ ├── de-DE.yml │ ├── en-US.yml │ ├── fr-FR.yml │ ├── nl-NL.yml │ └── sv-SE.yml │ ├── parties.json │ ├── plugin.yml │ ├── voted-for-party-cache.json │ └── votes.yml ├── version ├── build.gradle └── src │ └── main │ └── kotlin │ └── me │ └── clip │ └── voteparty │ └── version │ ├── EffectType.kt │ └── VersionHook.kt ├── version_new ├── build.gradle └── src │ └── main │ └── kotlin │ └── me │ └── clip │ └── voteparty │ └── version │ └── VersionHookNew.kt └── version_old ├── build.gradle └── src └── main └── kotlin └── me └── clip └── voteparty └── version └── VersionHookOld.kt /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-latest 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - uses: actions/checkout@v4 24 | - uses: actions/setup-java@v4 25 | with: 26 | distribution: 'zulu' 27 | java-version: '11' 28 | - name: Gradle Test Build 29 | run: ./gradlew clean shadowJar 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | 7 | # IntelliJ 8 | .idea 9 | 10 | out 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Glare 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

Welcome to VoteParty 👋

3 |

4 | Version 5 | 6 | Documentation 7 | 8 | 9 | License: MIT 10 | 11 |

12 | 13 | > Give rewards to all online players when the server gets a certain amount of votes! 1.8+ 14 | 15 | ## Author 16 | 17 | 👤 **Glare** 18 | 19 | * Website: https://glaremasters.me/ 20 | * Github: [@darbyjack](https://github.com/darbyjack) 21 | 22 | ## Get Help 23 | [![Discord](https://discordapp.com/api/guilds/164280494874165248/widget.png?style=banner2)](https://discord.gg/helpchat) 24 | 25 | ## 🤝 Contributing 26 | 27 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/darbyjack/VoteParty/issues). 28 | 29 | ## Show your support 30 | 31 | Give a ⭐️ if this project helped you! 32 | 33 | ## 📝 License 34 | 35 | Copyright © 2021 [darbyjack](https://github.com/darbyjack).
36 | This project is [MIT](https://github.com/darbyjack/VoteParty/blob/master/LICENSE.md) licensed. 37 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.filters.ReplaceTokens 2 | 3 | plugins { 4 | id 'org.jetbrains.kotlin.jvm' version '2.0.0' 5 | id 'io.github.goooler.shadow' version '8.1.7' apply false 6 | id "com.github.ben-manes.versions" version "0.51.0" 7 | id "net.kyori.indra" version "3.1.3" 8 | id "net.kyori.indra.publishing" version "3.1.3" 9 | } 10 | 11 | allprojects { 12 | apply plugin: 'org.jetbrains.kotlin.jvm' 13 | apply plugin: 'net.kyori.indra' 14 | apply plugin: 'net.kyori.indra.publishing' 15 | 16 | archivesBaseName = 'VoteParty' 17 | group 'me.clip' 18 | version '2.40-SNAPSHOT' 19 | 20 | repositories { 21 | mavenCentral() 22 | 23 | maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } 24 | maven { url = "https://repo.aikar.co/content/groups/aikar/" } 25 | maven { url = "https://papermc.io/repo/repository/maven-public/" } 26 | maven { url = "https://repo.extendedclip.com/content/repositories/placeholderapi/" } 27 | maven { url = "https://repo.glaremasters.me/repository/public/" } 28 | } 29 | 30 | dependencies { 31 | // kotlin 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 33 | 34 | // Support for materials across all versions 35 | implementation 'com.github.cryptomorin:XSeries:11.1.0' 36 | } 37 | 38 | indra { 39 | mitLicense() 40 | 41 | javaVersions { 42 | target(8) 43 | } 44 | 45 | github("darbyjack", "voteparty") { 46 | publishing(true) 47 | } 48 | 49 | publishAllTo("nexus", "https://repo.glaremasters.me/repository/random-stuff/") 50 | } 51 | 52 | compileJava { 53 | options.compilerArgs += ["-parameters"] 54 | } 55 | 56 | compileKotlin { 57 | kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8 58 | kotlinOptions.javaParameters = true 59 | } 60 | } 61 | 62 | apply plugin: 'io.github.goooler.shadow' 63 | 64 | shadowJar { 65 | minimize() 66 | relocate("co.aikar.commands", "me.clip.voteparty.libs.acf") 67 | relocate("co.aikar.locales", "me.clip.voteparty.libs.locales") 68 | relocate("ch.jalu.configme", "me.clip.voteparty.libs.configme") 69 | relocate("org.inventivetalent", "me.clip.voteparty.libs.inventivetalent") 70 | relocate("net.kyori", "me.clip.voteparty.libs.kyori") 71 | relocate("com.cryptomorin.xseries", "me.clip.voteparty.libs.xseries") 72 | relocate("kotlin", "me.clip.voteparty.libs.kotlin") 73 | relocate("org.bstats", "me.clip.voteparty.libs.bstats") 74 | archiveFileName = "VoteParty-${project.version}.jar" 75 | } 76 | 77 | 78 | dependencies { 79 | 80 | // spigot 81 | compileOnly "org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT" 82 | 83 | // config 84 | implementation "ch.jalu:configme:1.3.0" 85 | 86 | // placeholderapi 87 | compileOnly "me.clip:placeholderapi:2.11.6" 88 | 89 | // NuVotifier hook 90 | compileOnly files("libs/nuvotifier-2.7.3.jar") 91 | 92 | // command handler 93 | implementation "co.aikar:acf-paper:0.5.1-SNAPSHOT" 94 | 95 | // bstats 96 | implementation 'org.bstats:bstats-bukkit:3.0.2' 97 | 98 | // json stuff 99 | implementation 'net.kyori:adventure-platform-bukkit:4.3.3' 100 | implementation 'net.kyori:adventure-api:4.17.0' 101 | implementation 'net.kyori:adventure-text-minimessage:4.17.0' 102 | 103 | implementation project(":version") 104 | implementation project(":version_old") 105 | implementation project(":version_new") 106 | } 107 | 108 | processResources { 109 | filter ReplaceTokens, tokens: [version: version] 110 | } 111 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /src/main/resources/languages/en-US.yml 3 | translation: /src/main/resources/languages/%locale%.yml 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /libs/nuvotifier-2.7.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/libs/nuvotifier-2.7.3.jar -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "VP" 2 | include 'version' 3 | include 'version_old' 4 | include 'version_new' 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/me/clip/voteparty/plugin/VotePartyPlugin.java: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.plugin; 2 | 3 | import me.clip.voteparty.VoteParty; 4 | import org.bstats.bukkit.Metrics; 5 | import org.bukkit.plugin.ServicePriority; 6 | import org.bukkit.plugin.java.JavaPlugin; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | public final class VotePartyPlugin extends JavaPlugin 10 | { 11 | private VoteParty voteParty; 12 | 13 | @Override 14 | public void onEnable() 15 | { 16 | this.voteParty = new VoteParty(this); 17 | this.voteParty.load(); 18 | 19 | new Metrics(this, 17932); 20 | 21 | getServer().getServicesManager().register(VoteParty.class, this.voteParty, this, ServicePriority.Normal); 22 | } 23 | 24 | @Override 25 | public void onDisable() 26 | { 27 | if (this.voteParty != null) 28 | { 29 | this.voteParty.kill(); 30 | } 31 | 32 | this.voteParty = null; 33 | 34 | getServer().getServicesManager().unregisterAll(this); 35 | } 36 | 37 | 38 | @Nullable 39 | public VoteParty getVoteParty() 40 | { 41 | return this.voteParty; 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/VoteParty.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty 2 | 3 | import ch.jalu.configme.SettingsManager 4 | import co.aikar.commands.PaperCommandManager 5 | import com.google.gson.Gson 6 | import me.clip.voteparty.base.State 7 | import me.clip.voteparty.bungee.NuVotifierBungeeHandler 8 | import me.clip.voteparty.cmds.CommandVoteParty 9 | import me.clip.voteparty.conf.VoteDataConfiguration 10 | import me.clip.voteparty.conf.VotePartyConfiguration 11 | import me.clip.voteparty.conf.sections.VoteSettings 12 | import me.clip.voteparty.conf.sections.HookSettings 13 | import me.clip.voteparty.conf.sections.PartySettings 14 | import me.clip.voteparty.conf.sections.PluginSettings 15 | import me.clip.voteparty.conf.sections.VoteData 16 | import me.clip.voteparty.data.impl.PartiesCacheGson 17 | import me.clip.voteparty.data.impl.VotedForPartyCacheGson 18 | import me.clip.voteparty.exte.color 19 | import me.clip.voteparty.exte.runTaskTimer 20 | import me.clip.voteparty.exte.runTaskTimerAsync 21 | import me.clip.voteparty.handler.LeaderboardHandler 22 | import me.clip.voteparty.handler.PartyHandler 23 | import me.clip.voteparty.handler.VotesHandler 24 | import me.clip.voteparty.listener.CrateListener 25 | import me.clip.voteparty.listener.HooksListenerNuVotifier 26 | import me.clip.voteparty.listener.VotesListener 27 | import me.clip.voteparty.placeholders.VotePartyPlaceholders 28 | import me.clip.voteparty.plugin.VotePartyPlugin 29 | import me.clip.voteparty.user.UsersHandler 30 | import me.clip.voteparty.util.JarFileWalker 31 | import me.clip.voteparty.util.UpdateChecker 32 | import me.clip.voteparty.version.VersionHook 33 | import me.clip.voteparty.version.VersionHookNew 34 | import me.clip.voteparty.version.VersionHookOld 35 | import net.kyori.adventure.platform.bukkit.BukkitAudiences 36 | import org.bukkit.Bukkit 37 | import org.bukkit.OfflinePlayer 38 | import org.bukkit.command.ConsoleCommandSender 39 | import org.bukkit.configuration.file.YamlConfiguration 40 | import org.bukkit.entity.Player 41 | import java.io.File 42 | import java.io.InputStream 43 | import java.util.Locale 44 | import java.util.logging.Level 45 | 46 | class VoteParty internal constructor(internal val plugin: VotePartyPlugin) : State 47 | { 48 | 49 | val votesHandler = VotesHandler(plugin) 50 | val partyHandler = PartyHandler(plugin) 51 | val usersHandler = UsersHandler(plugin) 52 | val leaderboardHandler = LeaderboardHandler(plugin) 53 | 54 | 55 | private var conf = null as? SettingsManager? 56 | private var voteData = null as? SettingsManager? 57 | private var audiences = null as? BukkitAudiences? 58 | private val cmds = PaperCommandManager(plugin) 59 | 60 | private val crateListener = CrateListener(plugin) 61 | private val votesListener = VotesListener(plugin) 62 | private val hooksListener = HooksListenerNuVotifier(plugin) 63 | private val votedForPartyCache = VotedForPartyCacheGson(plugin) 64 | private val partiesCache = PartiesCacheGson(plugin) 65 | 66 | private var hook = null as? VersionHook? 67 | private var papi = null as? VotePartyPlaceholders? 68 | 69 | 70 | override fun load() 71 | { 72 | logo(plugin.server.consoleSender) 73 | 74 | this.audiences = BukkitAudiences.create(plugin) 75 | 76 | loadConf() 77 | loadVoteData() 78 | loadCmds() 79 | loadHook() 80 | loadPapi() 81 | 82 | saveLang() 83 | loadLang() 84 | 85 | checkForUpdates() 86 | 87 | // handlers 88 | votesHandler.load() 89 | usersHandler.load() 90 | leaderboardHandler.load() 91 | 92 | // listeners 93 | crateListener.load() 94 | votesListener.load() 95 | 96 | // voted for party cache 97 | votedForPartyCache.load() 98 | 99 | // parties cache 100 | partiesCache.load() 101 | 102 | if (conf().getProperty(HookSettings.NUVOTIFIER).backend) 103 | { 104 | hooksListener.load() 105 | } 106 | 107 | if (conf().getProperty(HookSettings.NUVOTIFIER).pluginMessaging) { 108 | NuVotifierBungeeHandler(plugin).load() 109 | } 110 | 111 | // votes 112 | loadVotes() 113 | 114 | plugin.runTaskTimerAsync(conf().getProperty(PluginSettings.SAVE_INTERVAL).toLong() * 20L) 115 | { 116 | saveVotes() 117 | } 118 | 119 | plugin.runTaskTimerAsync(conf().getProperty(PluginSettings.PLAYER_SAVE_INTERVAL).toLong() * 20L) 120 | { 121 | usersHandler.saveAll() 122 | votedForPartyCache.save() 123 | partiesCache.save() 124 | } 125 | 126 | if (conf().getProperty(VoteSettings.REMINDER_ENABLED)) { 127 | plugin.runTaskTimer(conf().getProperty(VoteSettings.REMINDER_INTERVAL_SECONDS).toLong() * 20L) 128 | { 129 | votesHandler.sendVoteReminders() 130 | } 131 | } 132 | } 133 | 134 | override fun kill() 135 | { 136 | saveVotes() 137 | if (conf().getProperty(HookSettings.NUVOTIFIER).backend) 138 | { 139 | hooksListener.kill() 140 | } 141 | crateListener.kill() 142 | votesListener.kill() 143 | 144 | usersHandler.kill() 145 | leaderboardHandler.kill() 146 | votedForPartyCache.kill() 147 | partiesCache.kill() 148 | } 149 | 150 | 151 | private fun loadConf() 152 | { 153 | val file = plugin.dataFolder.resolve("config.yml") 154 | 155 | if (!file.exists()) 156 | { 157 | file.parentFile.mkdirs() 158 | file.createNewFile() 159 | } 160 | 161 | this.conf = VotePartyConfiguration(file) 162 | } 163 | 164 | private fun loadVoteData() 165 | { 166 | val file = plugin.dataFolder.resolve("votes.yml") 167 | 168 | if (!file.exists()) { 169 | file.parentFile.mkdirs() 170 | file.createNewFile() 171 | } 172 | 173 | this.voteData = VoteDataConfiguration(file) 174 | } 175 | 176 | private fun saveLang() 177 | { 178 | JarFileWalker.walk("/languages") 179 | { path, stream -> 180 | 181 | if (stream == null) 182 | { 183 | return@walk // do nothing if the stream couldn't be opened 184 | } 185 | 186 | val file = plugin.dataFolder.resolve(path.toString().drop(1)).absoluteFile 187 | if (file.exists()) 188 | { 189 | mergeLanguage(stream, file) 190 | return@walk // language file was already created 191 | } 192 | 193 | file.parentFile.mkdirs() 194 | file.createNewFile() 195 | 196 | file.outputStream().use() 197 | { 198 | stream.copyTo(it) 199 | stream.close() 200 | } 201 | } 202 | } 203 | 204 | private fun mergeLanguage(stream: InputStream, outside: File) 205 | { 206 | val new = YamlConfiguration.loadConfiguration(stream.reader()) 207 | val old = YamlConfiguration.loadConfiguration(outside) 208 | 209 | for (path in new.getKeys(true)) 210 | { 211 | if (!old.contains(path)) { 212 | old.set(path, old.get(path, new.get(path))) 213 | } 214 | } 215 | old.save(outside) 216 | } 217 | 218 | private fun loadCmds() 219 | { 220 | if (conf().getProperty(PluginSettings.BRIGADIER)) 221 | { 222 | cmds.enableUnstableAPI("brigadier") 223 | } 224 | 225 | cmds.locales.defaultLocale = Locale.forLanguageTag(conf().getProperty(PluginSettings.LANGUAGE) ?: "en-US") 226 | cmds.usePerIssuerLocale(false, false) 227 | 228 | cmds.commandCompletions.registerCompletion("online") 229 | { 230 | plugin.server.onlinePlayers.map(Player::getName) 231 | } 232 | 233 | cmds.commandReplacements.addReplacement("vp", "vp|voteparty") 234 | 235 | cmds.registerCommand(CommandVoteParty(plugin)) 236 | } 237 | 238 | private fun loadHook() 239 | { 240 | this.hook = if (Bukkit.getBukkitVersion().substringBefore('-').substringAfter('.').substringBefore('.').toInt() >= 13) 241 | { 242 | VersionHookNew() 243 | } 244 | else 245 | { 246 | VersionHookOld() 247 | } 248 | } 249 | 250 | private fun loadPapi() 251 | { 252 | val papi = VotePartyPlaceholders(this) 253 | papi.register() 254 | 255 | this.papi = papi 256 | } 257 | 258 | 259 | private fun loadVotes() 260 | { 261 | votesHandler.setVotes(voteData().getProperty(VoteData.COUNTER)) 262 | } 263 | 264 | private fun saveVotes() 265 | { 266 | voteData().setProperty(VoteData.COUNTER, votesHandler.getVotes()) 267 | voteData().save() 268 | } 269 | 270 | 271 | private fun logo(sender: ConsoleCommandSender) 272 | { 273 | val logo = LOGO.replace("{plugin_version}", plugin.description.version).replace("{server_version}", plugin.server.version) 274 | sender.sendMessage(color(logo)) 275 | } 276 | 277 | private fun checkForUpdates() 278 | { 279 | UpdateChecker.check(plugin, 987) 280 | { 281 | when (it) 282 | { 283 | is UpdateChecker.UpdateResult.UP_TO_DATE -> 284 | { 285 | plugin.logger.info(it.message) 286 | } 287 | is UpdateChecker.UpdateResult.UNRELEASED -> 288 | { 289 | plugin.logger.warning(it.message) 290 | } 291 | is UpdateChecker.UpdateResult.NEW_UPDATE -> 292 | { 293 | plugin.logger.info("${it.message}: ${it.version}") 294 | } 295 | is UpdateChecker.UpdateResult.EXCEPTIONS -> 296 | { 297 | plugin.logger.log(Level.WARNING, it.message, it.throwable) 298 | } 299 | } 300 | } 301 | } 302 | 303 | 304 | fun loadLang() 305 | { 306 | plugin.dataFolder.resolve("languages").listFiles()?.filter() 307 | { 308 | it.extension.equals("yml", true) 309 | }?.forEach() 310 | { 311 | val locale = Locale.forLanguageTag(it.nameWithoutExtension) 312 | 313 | cmds.addSupportedLanguage(locale) 314 | cmds.locales.loadYamlLanguageFile(it, locale) 315 | } 316 | } 317 | 318 | 319 | fun conf(): SettingsManager 320 | { 321 | return checkNotNull(conf) 322 | } 323 | 324 | fun voteData(): SettingsManager 325 | { 326 | return checkNotNull(voteData) 327 | } 328 | 329 | fun hook(): VersionHook 330 | { 331 | return checkNotNull(hook) 332 | } 333 | 334 | fun manager(): PaperCommandManager 335 | { 336 | return cmds 337 | } 338 | 339 | fun audiences(): BukkitAudiences 340 | { 341 | return checkNotNull(audiences) 342 | } 343 | 344 | fun getVotes(): Int 345 | { 346 | return votesHandler.getVotes() 347 | } 348 | 349 | fun getVotesNeeded(): Int 350 | { 351 | return conf().getProperty(PartySettings.VOTES_NEEDED) 352 | } 353 | 354 | @Deprecated("This was only used in the PlaceholderAPI Placeholders. A new and improved method has been implemented", ReplaceWith("UserHandler#getVotesWithinRange")) 355 | fun getPlayerVotes(player: OfflinePlayer): Int 356 | { 357 | return usersHandler[player].votes().size 358 | } 359 | 360 | 361 | internal companion object 362 | { 363 | internal val GSON = Gson() 364 | internal val LOGO = 365 | """ 366 | 367 | &6 _ _ &d ____ 368 | &6/ )( \&d( _ \ 369 | &6\ \/ /&d ) __/ &3VoteParty &8v{plugin_version} 370 | &6 \__/ &d(__) &3Server Version: &8{server_version} 371 | 372 | """.trimIndent() 373 | } 374 | 375 | } 376 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/base/Addon.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.base 2 | 3 | import me.clip.voteparty.VoteParty 4 | import me.clip.voteparty.plugin.VotePartyPlugin 5 | import org.bukkit.Server 6 | import java.util.logging.Logger 7 | 8 | /** 9 | * Defines an aspect of the plugin that requires access to spigot api 10 | */ 11 | internal interface Addon 12 | { 13 | 14 | val plugin: VotePartyPlugin 15 | 16 | val server: Server 17 | get() = plugin.server 18 | 19 | val logger: Logger 20 | get() = plugin.logger 21 | 22 | val party: VoteParty 23 | get() = checkNotNull(plugin.voteParty) 24 | { 25 | "vote party is unavailable" 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/base/State.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.base 2 | 3 | /** 4 | * Defines an object that holds state and requires enable and disable logic 5 | */ 6 | internal interface State 7 | { 8 | 9 | /** 10 | * Holds logic for when this enables 11 | */ 12 | fun load() 13 | 14 | /** 15 | * Holds logic for when this is disabled 16 | */ 17 | fun kill() 18 | 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/bungee/NuVotifierBungeeHandler.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.bungee 2 | 3 | import com.google.gson.Gson 4 | import com.vexsoftware.votifier.model.Vote 5 | import me.clip.voteparty.base.Addon 6 | import me.clip.voteparty.base.State 7 | import me.clip.voteparty.conf.sections.HookSettings 8 | import me.clip.voteparty.conf.sections.VoteSettings 9 | import me.clip.voteparty.events.VoteReceivedEvent 10 | import me.clip.voteparty.plugin.VotePartyPlugin 11 | import org.bukkit.Bukkit 12 | import org.bukkit.entity.Player 13 | import org.bukkit.plugin.messaging.PluginMessageListener 14 | import java.nio.charset.StandardCharsets 15 | import java.util.regex.Pattern 16 | 17 | internal data class BungeeVote( 18 | val username: String, 19 | val address: String, 20 | val timestamp: String, 21 | val serviceName: String 22 | ) 23 | 24 | internal class NuVotifierBungeeHandler(override val plugin: VotePartyPlugin) : Addon, State, PluginMessageListener { 25 | private lateinit var channel: String 26 | private lateinit var usernameRegex: Pattern 27 | private val gson = Gson() 28 | 29 | override fun load() { 30 | this.channel = party.conf().getProperty(HookSettings.NUVOTIFIER).pluginMessageChannel 31 | usernameRegex = Pattern.compile(party.conf().getProperty(VoteSettings.NAME_REGEX)) 32 | 33 | Bukkit.getMessenger().registerIncomingPluginChannel(plugin, channel, this) 34 | Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, channel) 35 | } 36 | 37 | override fun kill() { 38 | Bukkit.getMessenger().unregisterIncomingPluginChannel(plugin, channel, this) 39 | Bukkit.getMessenger().unregisterOutgoingPluginChannel(plugin, channel) 40 | } 41 | 42 | override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray?) { 43 | if (!channel.equals(this.channel, ignoreCase = true)) { 44 | return 45 | } 46 | 47 | if (message == null) { 48 | return 49 | } 50 | 51 | val content = String(message, StandardCharsets.UTF_8) 52 | val vote = gson.fromJson(content, BungeeVote::class.java) 53 | 54 | if (party.conf().getProperty(VoteSettings.VALIDATE_NAMES) && !usernameRegex.matcher(vote.username).matches()) { 55 | plugin.logger.warning("A vote came through NuVotifier (username: ${vote.username}) which did not match the username regex. Throwing away.") 56 | return 57 | } 58 | 59 | val player = party.usersHandler[vote.username]?.player() ?: server.getOfflinePlayer(vote.username) 60 | val event = VoteReceivedEvent(player, vote.serviceName) 61 | server.pluginManager.callEvent(event) 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/cmds/CommandVoteParty.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.cmds 2 | 3 | import co.aikar.commands.BaseCommand 4 | import co.aikar.commands.CommandIssuer 5 | import co.aikar.commands.annotation.CommandAlias 6 | import co.aikar.commands.annotation.CommandCompletion 7 | import co.aikar.commands.annotation.CommandPermission 8 | import co.aikar.commands.annotation.Default 9 | import co.aikar.commands.annotation.Description 10 | import co.aikar.commands.annotation.Name 11 | import co.aikar.commands.annotation.Optional 12 | import co.aikar.commands.annotation.Subcommand 13 | import co.aikar.commands.annotation.Syntax 14 | import co.aikar.commands.annotation.Values 15 | import co.aikar.commands.bukkit.contexts.OnlinePlayer 16 | import me.clip.voteparty.base.Addon 17 | import me.clip.voteparty.conf.sections.PartySettings 18 | import me.clip.voteparty.conf.sections.VoteSettings 19 | import me.clip.voteparty.events.VoteReceivedEvent 20 | import me.clip.voteparty.exte.ADMIN_PERM 21 | import me.clip.voteparty.exte.CLAIM_PERM 22 | import me.clip.voteparty.exte.deserialize 23 | import me.clip.voteparty.exte.helpMenu 24 | import me.clip.voteparty.exte.msgAsString 25 | import me.clip.voteparty.exte.sendMessage 26 | import me.clip.voteparty.leaderboard.LeaderboardType 27 | import me.clip.voteparty.messages.Messages 28 | import me.clip.voteparty.plugin.VotePartyPlugin 29 | import net.kyori.adventure.identity.Identity 30 | import org.bukkit.OfflinePlayer 31 | import org.bukkit.entity.Player 32 | import java.util.* 33 | import java.util.concurrent.TimeUnit 34 | import kotlin.text.StringBuilder 35 | 36 | @CommandAlias("%vp") 37 | internal class CommandVoteParty(override val plugin: VotePartyPlugin) : BaseCommand(), Addon 38 | { 39 | 40 | @Subcommand("addvote") 41 | @Syntax(" [amount]") 42 | @Description("Add a vote to a player with the ability to trigger or not the rewards.") 43 | @CommandPermission(ADMIN_PERM) 44 | fun addVote( 45 | issuer: CommandIssuer, 46 | @Name("target") target: String, 47 | @Name("silent") @Default("false") silent: Boolean, 48 | @Name("amount") @Optional @Default("1") amount: Int 49 | ) { 50 | 51 | if (amount <= 0) 52 | { 53 | return sendMessage(issuer, Messages.ERROR__INVALID_NUMBER) 54 | } 55 | 56 | val user = party.usersHandler[target] ?: return sendMessage(issuer, Messages.ERROR__USER_NOT_FOUND) 57 | 58 | if (silent) 59 | { 60 | repeat(amount) { 61 | user.voted() 62 | } 63 | 64 | return sendMessage(issuer, Messages.VOTES__ADDED_TO_PLAYER, user.player(), "{count}", amount) 65 | } 66 | 67 | repeat(amount) { 68 | plugin.server.pluginManager.callEvent(VoteReceivedEvent(user.player(), "")) 69 | } 70 | 71 | return sendMessage(issuer, Messages.VOTES__ADDED_TO_PLAYER, user.player(), "{count}", amount) 72 | } 73 | 74 | @Subcommand("addpartyvote") 75 | @Syntax("") 76 | @Description("Add a Vote to the party") 77 | @CommandPermission(ADMIN_PERM) 78 | fun addPartyVote(issuer: CommandIssuer, @Default("1") amount: Int) 79 | { 80 | 81 | if (amount <= 0) 82 | { 83 | return sendMessage(issuer, Messages.ERROR__INVALID_NUMBER) 84 | } 85 | 86 | party.votesHandler.addVotes(amount) 87 | sendMessage(issuer, Messages.VOTES__VOTE_COUNTER_UPDATED) 88 | } 89 | 90 | @Subcommand("givecrate") 91 | @CommandCompletion("@online") 92 | @Syntax(" ") 93 | @Description("Give Crate") 94 | @CommandPermission(ADMIN_PERM) 95 | fun giveCrate(issuer: CommandIssuer, @Values("@online") target: OnlinePlayer, @Default("1") amount: Int) 96 | { 97 | if (amount <= 0) 98 | { 99 | return sendMessage(issuer, Messages.ERROR__INVALID_NUMBER) 100 | } 101 | 102 | sendMessage(issuer, Messages.CRATE__CRATE_GIVEN, target.player) 103 | sendMessage(currentCommandManager.getCommandIssuer(target.player), Messages.CRATE__CRATE_RECEIVED) 104 | 105 | target.player.inventory.addItem(party.partyHandler.buildCrate(amount)) 106 | } 107 | 108 | @Subcommand("setcounter") 109 | @Syntax("") 110 | @Description("Set Counter") 111 | @CommandPermission(ADMIN_PERM) 112 | fun setCounter(issuer: CommandIssuer, amount: Int) 113 | { 114 | if (amount < 0) 115 | { 116 | return sendMessage(issuer, Messages.ERROR__INVALID_NUMBER) 117 | } 118 | 119 | party.conf().setProperty(PartySettings.VOTES_NEEDED, amount) 120 | party.conf().save() 121 | 122 | sendMessage(issuer, Messages.VOTES__VOTES_NEEDED_UPDATED) 123 | } 124 | 125 | @Subcommand("top") 126 | @Syntax(" [page]") 127 | @Description("List top voters") 128 | @CommandPermission("voteparty.top") 129 | fun top(issuer: CommandIssuer, type: LeaderboardType, @Default("1") page: Int) 130 | { 131 | if (page <= 0) 132 | { 133 | return sendMessage(issuer, Messages.ERROR__INVALID_NUMBER) 134 | } 135 | 136 | 137 | val leaderboard = party.leaderboardHandler.getLeaderboard(type) 138 | ?: return sendMessage(issuer, Messages.ERROR__LEADERBOARD_NOT_FOUND, null, "{type}", type.displayName) 139 | 140 | val pages = leaderboard.data.chunked(10) 141 | if (page > pages.size) 142 | { 143 | return sendMessage(issuer, Messages.ERROR__INVALID_PAGE_NUMBER, null, "{max}", pages.size.toString()) 144 | } 145 | 146 | val actualPage = pages[page - 1] 147 | if (actualPage.isEmpty()) 148 | { 149 | return sendMessage(issuer, Messages.ERROR__INVALID_PAGE_NUMBER, null, "{max}", pages.size.toString()) 150 | } 151 | 152 | 153 | 154 | val message = StringBuilder() 155 | message.appendLine( 156 | msgAsString(issuer, Messages.TOP__HEADER) 157 | .replace("{type}", type.displayName) 158 | .replace("{page}", page.toString()) 159 | .replace("{total}", pages.size.toString()) 160 | ) 161 | 162 | message.appendLine() 163 | 164 | for ((index, leaderboardUser) in actualPage.withIndex()) { 165 | message.appendLine( 166 | msgAsString(issuer, Messages.TOP__LINE) 167 | .replace("{position}", (index + 1).toString()) 168 | .replace("{player}", leaderboardUser.user.name) 169 | .replace("{uuid}", leaderboardUser.user.uuid.toString()) 170 | .replace("{votes}", leaderboardUser.votes.toString()) 171 | ) 172 | } 173 | 174 | message.appendLine() 175 | 176 | message.append( 177 | msgAsString(issuer, Messages.TOP__FOOTER) 178 | .replace("{type}", type.displayName) 179 | .replace("{page}", page.toString()) 180 | .replace("{total}", pages.size.toString()) 181 | ) 182 | 183 | party.audiences().sender(issuer.getIssuer()).sendMessage(Identity.nil(), deserialize(message.toString())) 184 | } 185 | 186 | @Subcommand("checkvotes") 187 | @Syntax(" ") 188 | @CommandCompletion("@online") 189 | @Description("Check Votes") 190 | @CommandPermission(ADMIN_PERM) 191 | fun checkVotes(issuer: CommandIssuer, offlinePlayer: OfflinePlayer, amount: Long, unit: TimeUnit) 192 | { 193 | val count = party.usersHandler.getVoteCountSince(offlinePlayer, amount, unit) 194 | sendMessage( 195 | issuer, 196 | Messages.INFO__PLAYER_CHECK_VOTES, 197 | offlinePlayer, 198 | "{count}", 199 | count, 200 | "{amount}", 201 | amount, 202 | "{unit}", 203 | unit.toString().lowercase(Locale.getDefault()) 204 | ) 205 | } 206 | 207 | @Subcommand("totalvotes") 208 | @Syntax("") 209 | @CommandCompletion("@online") 210 | @Description("Total Votes") 211 | @CommandPermission(ADMIN_PERM) 212 | fun totalVotes(issuer: CommandIssuer, offlinePlayer: OfflinePlayer) 213 | { 214 | sendMessage(issuer, Messages.INFO__PLAYER_TOTAL_VOTES, offlinePlayer) 215 | } 216 | 217 | @Subcommand("resetvotes") 218 | @Syntax("") 219 | @CommandCompletion("@online") 220 | @Description("Reset Votes") 221 | @CommandPermission(ADMIN_PERM) 222 | fun resetVotes(issuer: CommandIssuer, offlinePlayer: OfflinePlayer) 223 | { 224 | party.usersHandler.reset(offlinePlayer) 225 | sendMessage(issuer, Messages.INFO__VOTE_COUNT_RESET, offlinePlayer) 226 | } 227 | 228 | @Subcommand("startparty") 229 | @Description("Start Party") 230 | @CommandPermission(ADMIN_PERM) 231 | fun startParty(issuer: CommandIssuer) 232 | { 233 | party.partyHandler.startParty() 234 | sendMessage(issuer, Messages.PARTY__FORCE_START_SUCCESSFUL) 235 | } 236 | 237 | @Subcommand("giveparty") 238 | @CommandCompletion("@players") 239 | @Description("Give Party") 240 | @Syntax("") 241 | @CommandPermission(ADMIN_PERM) 242 | fun giveParty(issuer: CommandIssuer, @Values("@players") target: OnlinePlayer) 243 | { 244 | if (target.player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) 245 | { 246 | return sendMessage(issuer, Messages.ERROR__DISABLED_WORLD) 247 | } 248 | 249 | if (party.conf().getProperty(PartySettings.USE_CRATE)) 250 | { 251 | target.player.inventory.addItem(party.partyHandler.buildCrate(1)) 252 | } 253 | else 254 | { 255 | party.partyHandler.runAll(target.player) 256 | } 257 | 258 | sendMessage(issuer, Messages.VOTES__PRIVATE_PARTY_GIVEN, target.player) 259 | sendMessage(currentCommandManager.getCommandIssuer(target.player), Messages.VOTES__PRIVATE_PARTY_RECEIVED) 260 | } 261 | 262 | @Subcommand("reload") 263 | @Description("Reload") 264 | @CommandPermission(ADMIN_PERM) 265 | fun reload(issuer: CommandIssuer) 266 | { 267 | party.conf().reload() 268 | party.loadLang() 269 | 270 | sendMessage(issuer, Messages.INFO__RELOADED) 271 | } 272 | 273 | @Subcommand("claim") 274 | @Description("Claim") 275 | @CommandPermission(CLAIM_PERM) 276 | fun claim(player: Player) 277 | { 278 | val user = party.usersHandler[player] 279 | 280 | if (user.claimable <= 0) 281 | { 282 | return sendMessage(currentCommandIssuer, Messages.CLAIM__NONE) 283 | } 284 | 285 | if (player.inventory.firstEmpty() == -1 && party.conf().getProperty(VoteSettings.CLAIMABLE_IF_FULL)) 286 | { 287 | return sendMessage(currentCommandIssuer, Messages.CLAIM__FULL) 288 | } 289 | 290 | party.votesHandler.runAll(player) 291 | user.claimable-- 292 | 293 | sendMessage(currentCommandIssuer, Messages.CLAIM__SUCCESS, null, "{claim}", user.claimable) 294 | } 295 | 296 | @Subcommand("claimall") 297 | @Description("Claim All") 298 | @CommandPermission(CLAIM_PERM) 299 | fun claimAll(player: Player) 300 | { 301 | val user = party.usersHandler[player] 302 | 303 | if (user.claimable <= 0) 304 | { 305 | return sendMessage(currentCommandIssuer, Messages.CLAIM__NONE) 306 | } 307 | 308 | for (i in 1..user.claimable) 309 | { 310 | if (player.inventory.firstEmpty() == -1 && party.conf().getProperty(VoteSettings.CLAIMABLE_IF_FULL)) 311 | { 312 | return sendMessage(currentCommandIssuer, Messages.CLAIM__FULL_ALL, null, "{claimed}", i, "{claim}", user.claimable) 313 | } 314 | 315 | party.votesHandler.runAll(player) 316 | user.claimable-- 317 | } 318 | sendMessage(currentCommandIssuer, Messages.CLAIM__SUCCESS_ALL) 319 | } 320 | 321 | @Subcommand("help") 322 | @Description("Help") 323 | @CommandPermission("voteparty.help") 324 | fun help(issuer: CommandIssuer) 325 | { 326 | party.audiences().sender(issuer.getIssuer()).sendMessage(Identity.nil(), helpMenu(issuer)) 327 | } 328 | 329 | @Default 330 | fun default(issuer: CommandIssuer) 331 | { 332 | sendMessage(issuer, Messages.INFO__VOTES_NEEDED) 333 | } 334 | 335 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/VoteDataConfiguration.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf 2 | 3 | import ch.jalu.configme.SettingsManagerImpl 4 | import ch.jalu.configme.configurationdata.ConfigurationDataBuilder 5 | import ch.jalu.configme.migration.PlainMigrationService 6 | import ch.jalu.configme.resource.YamlFileResource 7 | import me.clip.voteparty.conf.sections.VoteData 8 | import java.io.File 9 | 10 | internal class VoteDataConfiguration(file: File) : SettingsManagerImpl(YamlFileResource(file.toPath()), ConfigurationDataBuilder.createConfiguration(SECTIONS), PlainMigrationService()) 11 | { 12 | private companion object 13 | { 14 | private val SECTIONS = listOf( 15 | VoteData::class.java 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/VotePartyConfiguration.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf 2 | 3 | import ch.jalu.configme.SettingsManagerImpl 4 | import ch.jalu.configme.configurationdata.ConfigurationDataBuilder 5 | import ch.jalu.configme.resource.YamlFileResource 6 | import me.clip.voteparty.conf.migrations.VoteMigrationService 7 | import me.clip.voteparty.conf.sections.CrateSettings 8 | import me.clip.voteparty.conf.sections.EffectsSettings 9 | import me.clip.voteparty.conf.sections.HookSettings 10 | import me.clip.voteparty.conf.sections.PartySettings 11 | import me.clip.voteparty.conf.sections.PluginSettings 12 | import me.clip.voteparty.conf.sections.VoteSettings 13 | import java.io.File 14 | 15 | internal class VotePartyConfiguration(file: File) : SettingsManagerImpl(YamlFileResource(file.toPath()), ConfigurationDataBuilder.createConfiguration(SECTIONS), VoteMigrationService()) 16 | { 17 | 18 | private companion object 19 | { 20 | 21 | private val SECTIONS = listOf( 22 | PluginSettings::class.java, 23 | HookSettings::class.java, 24 | CrateSettings::class.java, 25 | EffectsSettings::class.java, 26 | PartySettings::class.java, 27 | VoteSettings::class.java 28 | ) 29 | 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/mapper/SingleValueToCollectionMapper.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.mapper 2 | 3 | import ch.jalu.configme.beanmapper.MapperImpl 4 | import ch.jalu.configme.beanmapper.MappingContext 5 | import java.util.Collections 6 | 7 | 8 | /** 9 | * Extension of the bean mapper representing a simple migration where a property is changed from 10 | * a single value to a collection. This mapper wraps a single value into a collection whenever a 11 | * collection should be constructed. Example for issue #117. 12 | */ 13 | class SingleValueToCollectionMapper : MapperImpl() 14 | { 15 | override fun createCollection(context: MappingContext, value: Any): Collection<*>? 16 | { 17 | if (value !is Iterable<*>) 18 | { 19 | val coll = super.createCollection(context, Collections.singleton(value)) 20 | // Register error to trigger a rewrite with the proper structure 21 | context.registerError("Found single value where a collection is expected") 22 | return if (isCollectionWithOneElement(coll)) coll else null 23 | } 24 | return super.createCollection(context, value) 25 | } 26 | 27 | companion object 28 | { 29 | private fun isCollectionWithOneElement(coll: Collection<*>?): Boolean 30 | { 31 | return coll != null && coll.size == 1 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/migrations/VoteMigrationService.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.migrations 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData 4 | import ch.jalu.configme.migration.PlainMigrationService 5 | import ch.jalu.configme.resource.PropertyReader 6 | 7 | 8 | internal class VoteMigrationService : PlainMigrationService() 9 | { 10 | override fun performMigrations(reader: PropertyReader, configurationData: ConfigurationData): Boolean 11 | { 12 | return hasDeprecatedProperties(reader) 13 | } 14 | 15 | private fun hasDeprecatedProperties(reader: PropertyReader): Boolean 16 | { 17 | val deprecatedProperties = arrayOf("settings.counter.votes", "hooks.nuvotifier") 18 | for (deprecatedPath in deprecatedProperties) 19 | { 20 | if (reader.contains(deprecatedPath)) 21 | { 22 | return true 23 | } 24 | } 25 | return false 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/Command.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | import java.util.concurrent.ThreadLocalRandom 4 | 5 | internal data class Command(var chance: Double = 50.0, 6 | var command: List = listOf("")) 7 | { 8 | 9 | fun shouldExecute(): Boolean 10 | { 11 | return chance >= ThreadLocalRandom.current().nextDouble(100.0) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/Commands.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class Commands(var enabled: Boolean = true, 4 | var commands: List = listOf("")) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/Counter.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class Counter(var votes: Int = 0, 4 | var save_interval: Int = 60) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/CumulativeVoteCommands.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class CumulativeVoteCommands(var votes: Int = 5, 4 | var commands: List = listOf("")) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/CumulativeVoteRewards.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class CumulativeVoteRewards( 4 | var enabled: Boolean = false, 5 | var entries: List = listOf(CumulativeVoteCommands(5, listOf("eco give %player_name% 500"))) 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/CumulativeVoting.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class CumulativeVoting( 4 | var daily: CumulativeVoteRewards = CumulativeVoteRewards(false, listOf(CumulativeVoteCommands(5, listOf("give %player_name% STEAK 10")))), 5 | var weekly: CumulativeVoteRewards = CumulativeVoteRewards(false, listOf(CumulativeVoteCommands(5, listOf("give %player_name% STEAK 10")))), 6 | var monthly: CumulativeVoteRewards = CumulativeVoteRewards(false, listOf(CumulativeVoteCommands(5, listOf("give %player_name% STEAK 10")))), 7 | var yearly: CumulativeVoteRewards = CumulativeVoteRewards(false, listOf(CumulativeVoteCommands(5, listOf("give %player_name% STEAK 10")))), 8 | var total: CumulativeVoteRewards = CumulativeVoteRewards(false, listOf(CumulativeVoteCommands(5, listOf("give %player_name% STEAK 10")))) 9 | ) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/Effects.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class Effects(var enable: Boolean = true, 4 | var effects: List = listOf("SMOKE_NORMAL", "HEART"), 5 | var offsetX: Double = 0.0, 6 | var offsetY: Double = 0.0, 7 | var offsetZ: Double = 0.0, 8 | var speed: Double = 0.0, 9 | var count: Int = 3) 10 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/NuVotifier.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class NuVotifier( 4 | var backend: Boolean = true, 5 | var pluginMessaging: Boolean = false, 6 | var pluginMessageChannel: String = "nuvotifier:votes" 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/PermCommands.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class PermCommands(var permission: String = "", 4 | var commands: List = listOf("")) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/PermRewards.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class PermRewards(var enabled: Boolean = true, 4 | var permCommands: List = listOf(PermCommands("my.special.permission", listOf("eco give %player_name% 500")))) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/RewardsPerEvent.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class RewardsPerEvent(var enabled: Boolean = true, 4 | var max_possible: Int = 1, 5 | var commands: List = listOf(Command(50.0, listOf("eco give %player_name% 100")), Command(70.0, listOf("give %player_name% STEAK 10")))) 6 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/VotesiteCommands.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class VotesiteCommands(var serviceName: String = "", 4 | var commands: List = listOf("")) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/objects/VotesiteRewards.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.objects 2 | 3 | internal data class VotesiteRewards(var enabled: Boolean = true, 4 | var votesiteCommands: List = listOf(VotesiteCommands("TestVote", listOf("eco give %player_name% 500")))) -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/CrateSettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.SettingsHolder 4 | import ch.jalu.configme.properties.Property 5 | import ch.jalu.configme.properties.PropertyInitializer.* 6 | import com.cryptomorin.xseries.XMaterial 7 | 8 | internal object CrateSettings : SettingsHolder 9 | { 10 | 11 | @JvmField 12 | val ENABLED: Property = newProperty("crate.enabled", true) 13 | 14 | @JvmField 15 | val LORE: Property> = newListProperty("crate.lore", "", "&7Place the chest in order to", "&7to receive rewards!", "") 16 | 17 | @JvmField 18 | val MATERIAL: Property = newBeanProperty(XMaterial::class.java, "crate.material", XMaterial.CHEST) 19 | 20 | @JvmField 21 | val NAME: Property = newProperty("crate.name", "&d&lVote&5&lParty &f&lCrate") 22 | 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/EffectsSettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.Comment 4 | import ch.jalu.configme.SettingsHolder 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration 6 | import ch.jalu.configme.properties.Property 7 | import ch.jalu.configme.properties.PropertyInitializer.newBeanProperty 8 | import me.clip.voteparty.conf.objects.Effects 9 | 10 | 11 | internal object EffectsSettings : SettingsHolder 12 | { 13 | 14 | @JvmField 15 | @Comment("Configuration for particles when party commands are being executed") 16 | val PARTY_COMMAND_EXECUTE: Property = newBeanProperty(Effects::class.java, "effects.party_commands_execute", Effects(true, listOf("SMOKE", "HEART"), 0.0, 0.0, 0.0, 0.1, 2)) 17 | 18 | @JvmField 19 | @Comment("Configuration for particles when a party starts") 20 | val PARTY_START: Property = newBeanProperty(Effects::class.java, "effects.party_start", Effects(true, listOf("SMOKE", "HEART"), 0.0, 0.0, 0.0, 0.1, 2)) 21 | 22 | @JvmField 23 | @Comment("Configuration for particles when a player votes") 24 | val VOTE: Property = newBeanProperty(Effects::class.java, "effects.vote", Effects(true, listOf("SMOKE", "HEART"), 0.0, 0.0, 0.0, 0.1, 2)) 25 | 26 | 27 | override fun registerComments(conf: CommentsConfiguration) 28 | { 29 | conf.setComment("effects", "Configuration for particle effects you can play", "throughout different parts of the plugin") 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/HookSettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.Comment 4 | import ch.jalu.configme.SettingsHolder 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration 6 | import ch.jalu.configme.properties.Property 7 | import ch.jalu.configme.properties.PropertyInitializer.newBeanProperty 8 | import ch.jalu.configme.properties.PropertyInitializer.newProperty 9 | import me.clip.voteparty.conf.objects.NuVotifier 10 | 11 | internal object HookSettings : SettingsHolder { 12 | 13 | @JvmField 14 | @Comment( 15 | "This property represents whether or not to listen to NuVotifier for incoming votes.", 16 | "If the backend is set to true, it assumes that the NuVotifier plugin is already enabled on the backend Spigot server,", 17 | "and pluginMessaging does not need to be enabled. If the backend is disabled, pluginMessaging should be enabled to allow", 18 | "NuVotifier to work on the proxy server. Additionally, make sure that the channel specified here matches the one set in", 19 | "your NuVotifier configuration, and that the \"method\" in your NuVotifier config is set to \"pluginMessaging\"." 20 | ) 21 | val NUVOTIFIER: Property = newBeanProperty( 22 | NuVotifier::class.java, "hooks.votifier", NuVotifier( 23 | backend = true, 24 | pluginMessaging = false, 25 | pluginMessageChannel = "nuvotifier:votes" 26 | ) 27 | ) 28 | 29 | override fun registerComments(conf: CommentsConfiguration) { 30 | conf.setComment( 31 | "hooks", 32 | "The hook part of the config allows you to configure which plugins you would like to hook into for votes.", 33 | "By default, the plugin will utilize NuVotifier and listen for it's vote events.", 34 | "If you would like to use the plugin without NuVotifier, just disable the hook!", 35 | "NOTE: Keep in mind that without being hooked into a vote plugin, the plugin will not automatically handle votes.", 36 | "You will be required to do everything manually.", 37 | "Over time, more plugins may become supported!" 38 | ) 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/PartySettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.Comment 4 | import ch.jalu.configme.SettingsHolder 5 | import ch.jalu.configme.properties.BeanProperty 6 | import ch.jalu.configme.properties.Property 7 | import ch.jalu.configme.properties.PropertyInitializer.* 8 | import me.clip.voteparty.conf.mapper.SingleValueToCollectionMapper 9 | import me.clip.voteparty.conf.objects.Command 10 | import me.clip.voteparty.conf.objects.Commands 11 | import me.clip.voteparty.conf.objects.PermCommands 12 | import me.clip.voteparty.conf.objects.PermRewards 13 | import me.clip.voteparty.conf.objects.RewardsPerEvent 14 | 15 | internal object PartySettings : SettingsHolder 16 | { 17 | 18 | @JvmField 19 | @Comment("The amount of votes needed for a party to occur") 20 | val VOTES_NEEDED: Property = newProperty("party.votes_needed", 50) 21 | 22 | @JvmField 23 | @Comment("Would you like to use a crate for the rewards?") 24 | val USE_CRATE: Property = newProperty("party.use_crate", false) 25 | 26 | @JvmField 27 | @Comment("The list of worlds where party rewards won't be given") 28 | val DISABLED_WORLDS: Property> = newListProperty("party.disabled_worlds", "") 29 | 30 | @JvmField 31 | @Comment("Choose to allow offline votes count towards the party") 32 | val OFFLINE_VOTES: Property = newProperty("party.offline_votes", true) 33 | 34 | @JvmField 35 | @Comment( 36 | "There are 3 different ways that a party can work.", 37 | "1) \"everyone\" - everyone can join the party whether they voted or not", 38 | "2) \"daily\" - everyone who voted in the past 24 hours can join the party", 39 | "3) \"party\" - everyone who voted in this specific party can join the party", 40 | "Set the mode below to one of the options above to specify how the party should function" 41 | ) 42 | val PARTY_MODE: Property = newProperty("party.party_mode", "everyone") 43 | 44 | @JvmField 45 | @Comment("The amount of time (in seconds) the server will wait to start the party after the amount needed has been achieved") 46 | val START_DELAY: Property = newProperty("party.start_delay", 15) 47 | 48 | @JvmField 49 | @Comment("The amount of time (in seconds) the server will wait between executing reward commands") 50 | val COMMAND_DELAY: Property = newProperty("party.command_delay", 1) 51 | 52 | @JvmField 53 | @Comment("Configuration for chance rewards to be given during a party.", "Add as many commands as you want, set their chance, and choose the max amount a player can earn!") 54 | val REWARD_COMMANDS: Property = BeanProperty(RewardsPerEvent::class.java, "party.reward_commands", RewardsPerEvent(true, 1, listOf(Command(50.0, listOf("eco give %player_name% 100")), Command(50.0, listOf("give %player_name% DIAMOND 6")), Command(50.0, listOf("give %player_name% IRON_INGOT 12")))), SingleValueToCollectionMapper()) 55 | 56 | @JvmField 57 | @Comment("Configuration for extra commands to be executed on players who have specific permission nodes when a party happens") 58 | val PERMISSION_PARTY_REWARDS: Property = newBeanProperty(PermRewards::class.java, "party.permission-rewards", PermRewards(true, listOf(PermCommands("my.special.permission", listOf("eco give %player_name% 500"))))) 59 | 60 | @JvmField 61 | @Comment("A list of rewards that will ALWAYS be given to a player during a party") 62 | val GUARANTEED_REWARDS: Property = newBeanProperty(Commands::class.java, "party.guaranteed_rewards", Commands(true, listOf("eco give %player_name% 10", "give %player_name% STEAK 8"))) 63 | 64 | @JvmField 65 | @Comment("Commands to be executed before a party is started") 66 | val PRE_PARTY_COMMANDS: Property = newBeanProperty(Commands::class.java, "party.pre_party_commands", Commands(true, listOf("broadcast Party will start soon!"))) 67 | 68 | @JvmField 69 | @Comment("Commands to be executed when a party has started") 70 | val PARTY_COMMANDS: Property = newBeanProperty(Commands::class.java, "party.party_commands", Commands(true, listOf("broadcast A Vote Party has started!"))) 71 | 72 | @JvmField 73 | @Comment("Commands to be executed when a party has ended") 74 | val POST_PARTY_COMMANDS: Property = newBeanProperty(Commands::class.java, "party.post_party_commands", Commands(false, listOf("broadcast The Vote Party has ended!"))) 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/PluginSettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.Comment 4 | import ch.jalu.configme.SettingsHolder 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration 6 | import ch.jalu.configme.properties.Property 7 | import ch.jalu.configme.properties.PropertyInitializer.newProperty 8 | 9 | internal object PluginSettings : SettingsHolder 10 | { 11 | 12 | @JvmField 13 | @Comment("The default language of the plugin") 14 | val LANGUAGE: Property = newProperty("settings.language", "en-US") 15 | 16 | @JvmField 17 | @Comment("The prefix of all the messages in the plugin") 18 | val PREFIX: Property = newProperty("settings.prefix", "&d&lVote&5&lParty &7&l» ") 19 | 20 | @JvmField 21 | @Comment("How often to save the current amount of votes (in seconds)") 22 | val SAVE_INTERVAL: Property = newProperty("settings.counter.save-interval", 300) 23 | 24 | @JvmField 25 | @Comment("How often do we want to save the player data (in seconds)") 26 | val PLAYER_SAVE_INTERVAL: Property = newProperty("settings.data.save-interval", 300) 27 | 28 | @JvmField 29 | @Comment("Do you want to save a player's data instantly on vote? This will happen along with the interval saving above.", 30 | "Some servers just prefer to save instantly to ensure all the data is there.") 31 | val SAVE_ON_VOTE: Property = newProperty("settings.data.save-on-vote", false) 32 | 33 | @JvmField 34 | @Comment("Would you like to enable Brigadier command support? (I think it does more than just pretty colors) 1.13+") 35 | val BRIGADIER: Property = newProperty("settings.brigadier", false); 36 | 37 | 38 | override fun registerComments(conf: CommentsConfiguration) 39 | { 40 | conf.setComment("settings", 41 | "VoteParty", 42 | "Creator: Clip & Glare", 43 | "Contributors: https://github.com/VoteParty/VoteParty/graphs/contributors", 44 | "Issues: https://github.com/VoteParty/VoteParty/issues", 45 | "Spigot: https://www.spigotmc.org/resources/987/", 46 | "Wiki: https://wiki.helpch.at/glares-plugins/voteparty", 47 | "Discord: https://helpch.at/discord") 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/VoteData.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.SettingsHolder 4 | import ch.jalu.configme.properties.Property 5 | import ch.jalu.configme.properties.PropertyInitializer 6 | 7 | internal object VoteData : SettingsHolder 8 | { 9 | @JvmField 10 | val COUNTER: Property = PropertyInitializer.newProperty("votes", 0) 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/conf/sections/VoteSettings.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.conf.sections 2 | 3 | import ch.jalu.configme.Comment 4 | import ch.jalu.configme.SettingsHolder 5 | import ch.jalu.configme.properties.BeanProperty 6 | import ch.jalu.configme.properties.Property 7 | import ch.jalu.configme.properties.PropertyInitializer.newBeanProperty 8 | import ch.jalu.configme.properties.PropertyInitializer.newProperty 9 | import me.clip.voteparty.conf.mapper.SingleValueToCollectionMapper 10 | import me.clip.voteparty.conf.objects.Command 11 | import me.clip.voteparty.conf.objects.Commands 12 | import me.clip.voteparty.conf.objects.CumulativeVoting 13 | import me.clip.voteparty.conf.objects.PermCommands 14 | import me.clip.voteparty.conf.objects.PermRewards 15 | import me.clip.voteparty.conf.objects.RewardsPerEvent 16 | import me.clip.voteparty.conf.objects.VotesiteCommands 17 | import me.clip.voteparty.conf.objects.VotesiteRewards 18 | 19 | internal object VoteSettings : SettingsHolder 20 | { 21 | 22 | @JvmField 23 | @Comment("Would you like to validate the usernames being sent from voting sites?") 24 | val VALIDATE_NAMES: Property = newProperty("voting.validate_names", false) 25 | 26 | @JvmField 27 | @Comment("This is the regex for username checking. The default should apply to most accounts, but you are given access to modify in case you need to.") 28 | val NAME_REGEX: Property = newProperty("voting.name_regex", "^[a-zA-Z0-9_]{2,16}$") 29 | 30 | @JvmField 31 | @Comment("Enable or disable the voting reminder.") 32 | val REMINDER_ENABLED: Property = newProperty("voting.reminder_enabled", true) 33 | 34 | @JvmField 35 | @Comment("This is how long (in hours) the plugin should check that it has been since a user has voted before reminding them to vote.") 36 | val REMINDER_INTERVAL: Property = newProperty("voting.reminder_interval", 24) 37 | 38 | @JvmField 39 | @Comment("This is how many votes the plugin should check that a user has in the last X amount of time (defined above) before reminding them to vote.", 40 | "For example, if you set the reminder interval to 24 hours, and the reminder threshold to 3, the plugin will check if the user has voted 3 times in the last 24 hours.", 41 | "If they have, they will not be reminded to vote until they have voted 3 times in the last 24 hours.") 42 | val REMINDER_THRESHOLD: Property = newProperty("voting.reminder_threshold", 3) 43 | 44 | @JvmField 45 | @Comment("How often in seconds should players be reminded to vote? (Default is 10 minutes)", 46 | "Note: A FULL reboot is required for this to take effect if changed after the plugin has been loaded.") 47 | val REMINDER_INTERVAL_SECONDS: Property = newProperty("voting.reminder_interval_seconds", 600) 48 | 49 | @JvmField 50 | @Comment("If a player's inventory is full when voting, do you want to send the vote to a /vote claim?") 51 | val CLAIMABLE_IF_FULL: Property = newProperty("voting.claim_if_full", true) 52 | 53 | @JvmField 54 | @Comment("Configuration for chance rewards to be given for voting.", "Add as many commands as you want, set their chance, and choose the max amount a player can earn!") 55 | val PER_VOTE_REWARDS: Property = BeanProperty(RewardsPerEvent::class.java, "voting.per_vote_rewards", RewardsPerEvent(true, 1, listOf(Command(50.0, listOf("eco give %player_name% 100")), Command(70.0, listOf("give %player_name% STEAK 10")))), SingleValueToCollectionMapper()) 56 | 57 | @JvmField 58 | @Comment("Configuration for extra commands to be executed on players who have specific permission nodes") 59 | val PERMISSION_VOTE_REWARDS: Property = newBeanProperty(PermRewards::class.java, "voting.permission-rewards", PermRewards(true, listOf(PermCommands("my.special.permission", listOf("eco give %player_name% 500"))))) 60 | 61 | @JvmField 62 | @Comment("A list of rewards that will ALWAYS be given to a player for voting") 63 | val GUARANTEED_REWARDS: Property = newBeanProperty(Commands::class.java, "voting.guaranteed_rewards", Commands(true, listOf("eco give %player_name% 10", "give %player_name% STEAK 8"))) 64 | 65 | @JvmField 66 | @Comment("A list of commands to run when it's the first time a player has voted (only works for online players)") 67 | val FIRST_TIME_REWARDS: Property = newBeanProperty(Commands::class.java, "voting.first_time_rewards", Commands(false, listOf("eco give %player_name% 100", "give %player_name% STEAK 10"))) 68 | 69 | @JvmField 70 | @Comment("Configuration for extra commands to be executed on players who voted on a specific website (only works for online players)", 71 | "Known Service Names:", 72 | "TopG.com", 73 | "PlanetMinecraft.com", 74 | "Minecraft-MP.com", 75 | "MinecraftServers.org", 76 | "Minecraft-Server.net") 77 | val VOTESITE_VOTE_REWARDS: Property = newBeanProperty(VotesiteRewards::class.java, "voting.votesite-rewards", VotesiteRewards(false, listOf(VotesiteCommands("TestVote", listOf("eco give %player_name% 500"))))) 78 | 79 | @JvmField 80 | @Comment("Global commands (such as a broadcast message) to be executed when a player votes") 81 | val GLOBAL_COMMANDS: Property = newBeanProperty(Commands::class.java, "voting.global_commands", Commands(true, listOf("broadcast %player_name% just voted! Only %voteparty_votes_required_party% more votes until a VoteParty!"))) 82 | 83 | @JvmField 84 | @Comment("Would you like players to be able to claim rewards for offline votes?", 85 | "Note: They will only be able to get credit for rewards if you have `offline_votes` enabled") 86 | val OFFLINE_VOTE_CLAIMING: Property = newProperty("voting.offline_vote_claiming.enabled", false) 87 | 88 | @JvmField 89 | @Comment("Would you like to notify the player when they login that they have votes to claim?") 90 | val OFFLINE_VOTE_CLAIMING_NOTIFY: Property = newProperty("voting.offline_vote_claiming.notify", false) 91 | 92 | @JvmField 93 | @Comment("Configuration for extra commands to be executed on players who have voted a specific amount of times in the past day, week, month, year, and all time.") 94 | val CUMULATIVE_VOTE_REWARDS: Property = newBeanProperty(CumulativeVoting::class.java, "voting.cumulative-rewards", CumulativeVoting()) 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/base/DatabaseVotePlayer.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.base 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | import me.clip.voteparty.user.User 6 | import java.util.UUID 7 | 8 | internal interface DatabaseVotePlayer : Addon, State 9 | { 10 | 11 | override fun load() 12 | 13 | override fun kill() 14 | 15 | 16 | fun load(uuid: UUID): User? 17 | 18 | fun save(data: User) 19 | 20 | 21 | fun load(uuid: Collection): Map 22 | { 23 | return uuid.associateWith(::load) 24 | } 25 | 26 | fun save(data: Collection) 27 | { 28 | data.forEach(::save) 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/base/PartiesCache.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.base 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | 6 | internal interface PartiesCache : Addon, State { 7 | 8 | override fun load() 9 | 10 | override fun kill() 11 | 12 | fun save() 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/base/VotedForPartyCache.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.base 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | 6 | internal interface VotedForPartyCache : Addon, State { 7 | 8 | override fun load() 9 | 10 | override fun kill() 11 | 12 | fun save() 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/impl/DatabaseVotePlayerGson.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.impl 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import me.clip.voteparty.data.base.DatabaseVotePlayer 6 | import me.clip.voteparty.plugin.VotePartyPlugin 7 | import me.clip.voteparty.user.User 8 | import java.util.UUID 9 | import java.util.logging.Level 10 | 11 | internal class DatabaseVotePlayerGson(override val plugin: VotePartyPlugin) : DatabaseVotePlayer 12 | { 13 | 14 | private lateinit var gson: Gson 15 | 16 | 17 | override fun load() 18 | { 19 | val builder = GsonBuilder().disableHtmlEscaping().enableComplexMapKeySerialization().setPrettyPrinting().serializeNulls() 20 | gson = builder.create() 21 | 22 | plugin.dataFolder.resolve("players").mkdirs() 23 | } 24 | 25 | override fun kill() 26 | { 27 | 28 | } 29 | 30 | 31 | override fun load(uuid: UUID): User? 32 | { 33 | return try 34 | { 35 | gson.fromJson(plugin.dataFolder.resolve("players").resolve("$uuid.json").readText(), User::class.java) 36 | } 37 | catch (ex: Exception) 38 | { 39 | logger.log(Level.SEVERE, "failed to load player:$uuid", ex) 40 | null 41 | } 42 | } 43 | 44 | override fun save(data: User) 45 | { 46 | try 47 | { 48 | plugin.dataFolder.resolve("players").resolve("${data.uuid}.json").writeText(gson.toJson(data, User::class.java)) 49 | } 50 | catch (ex: Exception) 51 | { 52 | logger.log(Level.SEVERE, "failed to save player:${data.uuid}", ex) 53 | } 54 | } 55 | 56 | override fun load(uuid: Collection): Map 57 | { 58 | if (uuid.isNotEmpty()) 59 | { 60 | return super.load(uuid) 61 | } 62 | 63 | val files = plugin.dataFolder.resolve("players").listFiles() ?: return emptyMap() 64 | 65 | return files.mapNotNull() 66 | { 67 | try 68 | { 69 | UUID.fromString(it.nameWithoutExtension) 70 | } 71 | catch (ex: Exception) 72 | { 73 | null 74 | } 75 | }.associateWith(::load) 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/impl/PartiesCacheGson.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.impl 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import com.google.gson.reflect.TypeToken 6 | import java.io.File 7 | import java.util.logging.Level 8 | import me.clip.voteparty.data.base.PartiesCache 9 | import me.clip.voteparty.plugin.VotePartyPlugin 10 | 11 | class PartiesCacheGson(override val plugin: VotePartyPlugin) : PartiesCache { 12 | 13 | private lateinit var gson: Gson 14 | private lateinit var file: File 15 | private lateinit var backupFile: File 16 | private val type = object : TypeToken>() {}.type 17 | 18 | override fun load() 19 | { 20 | val builder = GsonBuilder().setPrettyPrinting() 21 | gson = builder.create() 22 | 23 | file = plugin.dataFolder.resolve("parties.json") 24 | backupFile = plugin.dataFolder.resolve("parties.json.bak") 25 | 26 | if (!file.exists()) 27 | { 28 | file.parentFile.mkdirs() 29 | file.createNewFile() 30 | } 31 | 32 | try 33 | { 34 | if (file.length() == 0L) 35 | { 36 | party.partyHandler.setParties(mutableListOf()) 37 | } 38 | else 39 | { 40 | party.partyHandler.setParties(gson.fromJson(file.readText(), type)) 41 | } 42 | } 43 | catch (exception: Exception) 44 | { 45 | logger.log( 46 | Level.SEVERE, 47 | "failed to load voted for party cache. This can end up in data loss!" + System.lineSeparator() + 48 | "A backup of the ${file.name} file was saved to: ${backupFile.name}", 49 | exception 50 | ) 51 | 52 | if (!backupFile.exists()) 53 | { 54 | backupFile.createNewFile() 55 | } 56 | 57 | backupFile.writeText(file.readText()) 58 | } 59 | } 60 | 61 | override fun kill() 62 | { 63 | save() 64 | } 65 | 66 | override fun save() 67 | { 68 | try 69 | { 70 | file.writeText(gson.toJson(party.partyHandler.getParties(), type)) 71 | } 72 | catch (exception: Exception) 73 | { 74 | logger.log( 75 | Level.SEVERE, 76 | "failed to save parties cache. This can end up in data loss!" + System.lineSeparator() + 77 | "For backup purposes, the cached data is: " + party.partyHandler.getParties().joinToString(", "), 78 | exception 79 | ) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/data/impl/VotedForPartyCacheGson.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.data.impl 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import com.google.gson.reflect.TypeToken 6 | import me.clip.voteparty.data.base.VotedForPartyCache 7 | import me.clip.voteparty.plugin.VotePartyPlugin 8 | import java.io.File 9 | import java.util.UUID 10 | import java.util.logging.Level 11 | 12 | internal class VotedForPartyCacheGson(override val plugin: VotePartyPlugin) : VotedForPartyCache 13 | { 14 | 15 | private lateinit var gson: Gson 16 | private lateinit var file: File 17 | private val type = object : TypeToken>() {}.type 18 | 19 | override fun load() { 20 | val builder = GsonBuilder().setPrettyPrinting() 21 | gson = builder.create() 22 | 23 | file = plugin.dataFolder.resolve("voted-for-party-cache.json") 24 | 25 | if (!file.exists()) { 26 | file.parentFile.mkdirs() 27 | file.createNewFile() 28 | } 29 | 30 | try 31 | { 32 | party.partyHandler.voted = gson.fromJson(file.readText(), type) 33 | } 34 | catch (ex: Exception) 35 | { 36 | party.partyHandler.voted = mutableListOf() 37 | } 38 | } 39 | 40 | override fun kill() { 41 | save() 42 | } 43 | 44 | override fun save() { 45 | try 46 | { 47 | file.writeText(gson.toJson(party.partyHandler.voted, type)) 48 | } 49 | catch (ex: Exception) 50 | { 51 | logger.log(Level.SEVERE, "failed to save voted for party cache.", ex) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/events/PartyEndEvent.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.events 2 | 3 | import org.bukkit.event.Event 4 | import org.bukkit.event.HandlerList 5 | 6 | class PartyEndEvent : Event() 7 | { 8 | 9 | override fun getHandlers(): HandlerList 10 | { 11 | return handlerList 12 | } 13 | 14 | companion object 15 | { 16 | @JvmStatic 17 | val handlerList = HandlerList() 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/events/PartyStartEvent.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.events 2 | 3 | import org.bukkit.event.Cancellable 4 | import org.bukkit.event.Event 5 | import org.bukkit.event.HandlerList 6 | 7 | class PartyStartEvent : Event(), Cancellable 8 | { 9 | private var isCancelled = false 10 | 11 | 12 | override fun isCancelled(): Boolean 13 | { 14 | return isCancelled 15 | } 16 | 17 | override fun setCancelled(cancelled: Boolean) 18 | { 19 | isCancelled = cancelled 20 | } 21 | 22 | 23 | override fun getHandlers(): HandlerList 24 | { 25 | return handlerList 26 | } 27 | 28 | 29 | companion object 30 | { 31 | @JvmStatic 32 | val handlerList = HandlerList() 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/events/PrePartyEvent.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.events 2 | 3 | import org.bukkit.event.Cancellable 4 | import org.bukkit.event.Event 5 | import org.bukkit.event.HandlerList 6 | 7 | class PrePartyEvent : Event(), Cancellable 8 | { 9 | private var isCancelled = false 10 | 11 | 12 | override fun isCancelled(): Boolean 13 | { 14 | return isCancelled 15 | } 16 | 17 | override fun setCancelled(cancelled: Boolean) 18 | { 19 | isCancelled = cancelled 20 | } 21 | 22 | 23 | override fun getHandlers(): HandlerList 24 | { 25 | return handlerList 26 | } 27 | 28 | 29 | companion object 30 | { 31 | @JvmStatic 32 | val handlerList = HandlerList() 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/events/VoteReceivedEvent.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.events 2 | 3 | import org.bukkit.OfflinePlayer 4 | import org.bukkit.event.Cancellable 5 | import org.bukkit.event.Event 6 | import org.bukkit.event.HandlerList 7 | 8 | class VoteReceivedEvent(val player: OfflinePlayer, val vote: String) : Event(), Cancellable 9 | { 10 | 11 | private var isCancelled = false 12 | 13 | 14 | override fun isCancelled(): Boolean 15 | { 16 | return isCancelled 17 | } 18 | 19 | override fun setCancelled(cancelled: Boolean) 20 | { 21 | isCancelled = cancelled 22 | } 23 | 24 | 25 | override fun getHandlers(): HandlerList 26 | { 27 | return handlerList 28 | } 29 | 30 | 31 | companion object 32 | { 33 | @JvmStatic 34 | val handlerList = HandlerList() 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/exte/const.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.exte 2 | 3 | internal const val PREFIX = "&d&lV&dote&5&lP&5arty &7&l» " 4 | 5 | internal const val BASE_PERM = "voteparty.command" 6 | 7 | internal const val ADMIN_PERM = "$BASE_PERM.admin" 8 | internal const val CLAIM_PERM = "$BASE_PERM.claim" -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/exte/funcs.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.exte 2 | 3 | import co.aikar.commands.ACFUtil 4 | import co.aikar.commands.CommandIssuer 5 | import co.aikar.locales.MessageKeyProvider 6 | import me.clip.placeholderapi.PlaceholderAPI 7 | import me.clip.voteparty.base.Addon 8 | import me.clip.voteparty.conf.objects.Command 9 | import me.clip.voteparty.conf.sections.PluginSettings 10 | import net.kyori.adventure.identity.Identity 11 | import net.kyori.adventure.text.Component 12 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 13 | import org.bukkit.Bukkit 14 | import org.bukkit.ChatColor 15 | import org.bukkit.Material 16 | import org.bukkit.OfflinePlayer 17 | import org.bukkit.inventory.ItemStack 18 | import org.bukkit.inventory.meta.ItemMeta 19 | import org.bukkit.plugin.Plugin 20 | import org.bukkit.scheduler.BukkitRunnable 21 | 22 | private val serializer = LegacyComponentSerializer.legacyAmpersand() 23 | 24 | internal fun color(message: String): String 25 | { 26 | return ChatColor.translateAlternateColorCodes('&', message) 27 | } 28 | 29 | internal fun deserialize(message: String): Component 30 | { 31 | return serializer.deserialize(color(message)) 32 | } 33 | 34 | internal fun formMessage(player: OfflinePlayer, message: String): String 35 | { 36 | return color(PlaceholderAPI.setPlaceholders(player, message)) 37 | } 38 | 39 | internal fun Addon.sendMessage(receiver: CommandIssuer, message: MessageKeyProvider, placeholderTarget: OfflinePlayer? = null, vararg replacements: Any = emptyArray()) 40 | { 41 | var msg = receiver.manager.locales.getMessage(receiver, message) 42 | 43 | if (replacements.isNotEmpty() && replacements.size % 2 == 0) 44 | { 45 | msg = ACFUtil.replaceStrings(msg, *replacements.map(Any::toString).toTypedArray()) 46 | } 47 | 48 | val result = formMessage(Bukkit.getOfflinePlayer(placeholderTarget?.uniqueId ?: receiver.uniqueId), (party.conf().getProperty(PluginSettings.PREFIX) ?: PREFIX) + msg) 49 | 50 | party.audiences().sender(receiver.getIssuer()).sendMessage(Identity.nil(), serializer.deserialize(result)) 51 | } 52 | 53 | internal fun msgAsString(issuer: CommandIssuer, key: MessageKeyProvider): String 54 | { 55 | return issuer.manager.locales.getMessage(issuer, key) 56 | } 57 | 58 | 59 | internal fun Plugin.runTaskTimer(period: Long, task: BukkitRunnable.() -> Unit) 60 | { 61 | object : BukkitRunnable() 62 | { 63 | override fun run() 64 | { 65 | task.invoke(this) 66 | } 67 | }.runTaskTimer(this, 0L, period) 68 | } 69 | 70 | internal fun Plugin.runTaskTimerAsync(period: Long, task: BukkitRunnable.() -> Unit) 71 | { 72 | object : BukkitRunnable() 73 | { 74 | override fun run() 75 | { 76 | task.invoke(this) 77 | } 78 | }.runTaskTimerAsynchronously(this, 0L, period) 79 | } 80 | 81 | internal fun Plugin.runTaskLater(delay: Long, task: () -> Unit) 82 | { 83 | server.scheduler.runTaskLater(this, task, delay) 84 | } 85 | 86 | 87 | internal fun Collection.takeRandomly(amount: Int): Collection 88 | { 89 | return filter(Command::shouldExecute).shuffled().take(amount) 90 | } 91 | 92 | 93 | internal fun item(type: Material, amount: Int, function: ItemMeta.() -> Unit = {}): ItemStack 94 | { 95 | return ItemStack(type, amount).meta(function) 96 | } 97 | 98 | internal fun ItemStack.meta(function: ItemMeta.() -> Unit): ItemStack 99 | { 100 | itemMeta = itemMeta?.apply(function) 101 | 102 | return this 103 | } 104 | 105 | internal var ItemMeta.name: String 106 | get() = displayName 107 | set(value) 108 | { 109 | setDisplayName(color(value)) 110 | } 111 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/exte/texts.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.exte 2 | 3 | import co.aikar.commands.CommandIssuer 4 | import me.clip.voteparty.messages.Messages 5 | import net.kyori.adventure.text.Component 6 | import net.kyori.adventure.text.minimessage.MiniMessage 7 | import java.util.* 8 | 9 | fun helpMenu(issuer: CommandIssuer): Component 10 | { 11 | val mini = MiniMessage.miniMessage() 12 | val builder = Component.text() 13 | val lineText = msgAsString(issuer, Messages.HELP__LINE_TEXT) 14 | val lineHoverTemplate = msgAsString(issuer, Messages.HELP__LINE_HOVER) 15 | 16 | // Header 17 | builder.append(mini.deserialize(msgAsString(issuer, Messages.HELP__HEADER))).append(Component.newline()) 18 | 19 | // Commands 20 | issuer.manager.getRootCommand("vp").subCommands.entries().forEach { 21 | val key = it.key 22 | val cmd = it.value 23 | if (key != "__default") 24 | { 25 | val updatedHover = lineHoverTemplate 26 | .replace("{text}", cmd.helpText) 27 | .replace("{desc}", msgAsString(issuer, Messages.valueOf("DESCRIPTIONS__" + key.uppercase(Locale.getDefault())))) 28 | .replace("{cmd}", it.key) 29 | .replace("{args}", cmd.syntaxText) 30 | .replace("{perm}", if (key == "help") "" else ADMIN_PERM) 31 | 32 | builder.append(mini.deserialize(lineText.replace("{cmd}", it.key).replace("{line-hover}", updatedHover))) 33 | } 34 | } 35 | 36 | // Footer 37 | builder.append((mini.deserialize(msgAsString(issuer, Messages.HELP__FOOTER)))) 38 | 39 | return builder.build() 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/handler/LeaderboardHandler.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.handler 2 | 3 | import com.google.common.cache.CacheBuilder 4 | import com.google.common.cache.CacheLoader 5 | import com.google.common.cache.LoadingCache 6 | import me.clip.voteparty.base.Addon 7 | import me.clip.voteparty.base.State 8 | import me.clip.voteparty.leaderboard.Leaderboard 9 | import me.clip.voteparty.leaderboard.LeaderboardType 10 | import me.clip.voteparty.plugin.VotePartyPlugin 11 | import java.util.concurrent.TimeUnit 12 | 13 | class LeaderboardHandler(override val plugin: VotePartyPlugin) : Addon, State 14 | { 15 | private val cache: LoadingCache = CacheBuilder.newBuilder().refreshAfterWrite(2, TimeUnit.MINUTES) 16 | .build(object : CacheLoader() 17 | { 18 | override fun load(key: LeaderboardType): Leaderboard 19 | { 20 | return Leaderboard(key, plugin.voteParty?.usersHandler?.getUsersWithVotesWithinRange(key.start.invoke(), key.end.invoke()) ?: emptyList()) 21 | } 22 | }) 23 | 24 | override fun load() 25 | { 26 | LeaderboardType.values.forEach() 27 | { type -> 28 | cache.put(type, Leaderboard(type, plugin.voteParty?.usersHandler?.getUsersWithVotesWithinRange(type.start.invoke(), type.end.invoke()) ?: emptyList())) 29 | } 30 | } 31 | 32 | override fun kill() 33 | { 34 | cache.invalidateAll() 35 | } 36 | 37 | fun getLeaderboard(type: LeaderboardType): Leaderboard? 38 | { 39 | return cache.get(type) 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/handler/PartyHandler.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.handler 2 | 3 | import java.time.LocalDateTime 4 | import java.time.ZoneId 5 | import me.clip.voteparty.base.Addon 6 | import me.clip.voteparty.conf.sections.CrateSettings 7 | import me.clip.voteparty.conf.sections.EffectsSettings 8 | import me.clip.voteparty.conf.sections.PartySettings 9 | import me.clip.voteparty.events.PartyEndEvent 10 | import me.clip.voteparty.events.PartyStartEvent 11 | import me.clip.voteparty.events.PrePartyEvent 12 | import me.clip.voteparty.exte.color 13 | import me.clip.voteparty.exte.formMessage 14 | import me.clip.voteparty.exte.meta 15 | import me.clip.voteparty.exte.name 16 | import me.clip.voteparty.exte.runTaskLater 17 | import me.clip.voteparty.exte.runTaskTimer 18 | import me.clip.voteparty.exte.sendMessage 19 | import me.clip.voteparty.exte.takeRandomly 20 | import me.clip.voteparty.messages.Messages 21 | import me.clip.voteparty.plugin.VotePartyPlugin 22 | import me.clip.voteparty.version.EffectType 23 | import org.bukkit.Bukkit 24 | import org.bukkit.Material 25 | import org.bukkit.entity.Player 26 | import org.bukkit.inventory.ItemStack 27 | import java.util.UUID 28 | import java.util.concurrent.TimeUnit 29 | 30 | class PartyHandler(override val plugin: VotePartyPlugin) : Addon 31 | { 32 | 33 | var voted = mutableListOf() 34 | private var parties = mutableListOf() 35 | 36 | fun getParties(): MutableList { 37 | return parties 38 | } 39 | 40 | fun setParties(new: MutableList) 41 | { 42 | parties = new 43 | } 44 | 45 | fun addParties(vararg new: Long) 46 | { 47 | new.forEach { parties.add(it) } 48 | } 49 | 50 | fun getPartiesSince(time: LocalDateTime): Int 51 | { 52 | val timeEpoch = time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 53 | 54 | return parties.count { partyEpoch -> partyEpoch > timeEpoch } 55 | } 56 | 57 | fun giveRandomPartyRewards(player: Player) 58 | { 59 | if (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) { 60 | return 61 | } 62 | 63 | val settings = party.conf().getProperty(PartySettings.REWARD_COMMANDS) 64 | 65 | if (!settings.enabled || settings.max_possible <= 0 || settings.commands.isEmpty()) 66 | { 67 | return 68 | } 69 | 70 | if (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) { 71 | return 72 | } 73 | 74 | val iter = settings.commands.takeRandomly(settings.max_possible).iterator() 75 | 76 | plugin.runTaskTimer(party.conf().getProperty(PartySettings.COMMAND_DELAY).toLong() * 20L) 77 | { 78 | if (!iter.hasNext()) 79 | { 80 | return@runTaskTimer cancel() 81 | } 82 | 83 | runPartyCommandEffects(player) 84 | iter.next().command.forEach() 85 | { command -> 86 | server.dispatchCommand(server.consoleSender, formMessage (player, command)) 87 | } 88 | } 89 | } 90 | 91 | fun giveGuaranteedPartyRewards(player: Player) 92 | { 93 | val settings = party.conf().getProperty(PartySettings.GUARANTEED_REWARDS) 94 | 95 | executeCommands(settings.enabled, settings.commands, player) 96 | } 97 | 98 | fun givePermissionPartyRewards(player: Player) 99 | { 100 | if (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) { 101 | return 102 | } 103 | 104 | val settings = party.conf().getProperty(PartySettings.PERMISSION_PARTY_REWARDS) 105 | 106 | if (!settings.enabled || settings.permCommands.isEmpty()) 107 | { 108 | return 109 | } 110 | 111 | if (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) { 112 | return 113 | } 114 | 115 | settings.permCommands.filter { player.hasPermission(it.permission) }.forEach() 116 | { perm -> 117 | perm.commands.forEach() 118 | { command -> 119 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 120 | } 121 | 122 | } 123 | } 124 | 125 | fun runAll(player: Player) 126 | { 127 | giveRandomPartyRewards(player) 128 | giveGuaranteedPartyRewards(player) 129 | givePermissionPartyRewards(player) 130 | } 131 | 132 | fun runPrePartyCommands() 133 | { 134 | val settings = party.conf().getProperty(PartySettings.PRE_PARTY_COMMANDS) 135 | 136 | executeCommands(settings.enabled, settings.commands) 137 | } 138 | 139 | fun runPartyCommands() 140 | { 141 | val settings = party.conf().getProperty(PartySettings.PARTY_COMMANDS) 142 | 143 | executeCommands(settings.enabled, settings.commands) 144 | } 145 | 146 | fun runPostPartyCommands() 147 | { 148 | val settings = party.conf().getProperty(PartySettings.POST_PARTY_COMMANDS) 149 | 150 | executeCommands(settings.enabled, settings.commands) 151 | } 152 | 153 | fun runPartyStartEffects() 154 | { 155 | val settings = party.conf().getProperty(EffectsSettings.PARTY_START) 156 | 157 | executeEffects(settings.enable, settings.effects, server.onlinePlayers, 158 | settings.offsetX, settings.offsetY, settings.offsetZ, 159 | settings.speed, settings.count) 160 | } 161 | 162 | fun runPartyCommandEffects(player: Player) 163 | { 164 | val settings = party.conf().getProperty(EffectsSettings.PARTY_COMMAND_EXECUTE) 165 | 166 | executeEffects(settings.enable, settings.effects, listOf(player), 167 | settings.offsetX, settings.offsetY, settings.offsetZ, 168 | settings.speed, settings.count) 169 | } 170 | 171 | 172 | fun buildCrate(amount: Int): ItemStack 173 | { 174 | val item = party.conf().getProperty(CrateSettings.MATERIAL).parseItem() ?: ItemStack(Material.CHEST, 1) 175 | item.amount = amount 176 | 177 | return item.meta() 178 | { 179 | name = party.conf().getProperty(CrateSettings.NAME) ?: "Vote Party Crate" 180 | lore = party.conf().getProperty(CrateSettings.LORE).map(::color) 181 | } 182 | } 183 | 184 | fun startParty() 185 | { 186 | 187 | val prePartyEvent = PrePartyEvent() 188 | Bukkit.getPluginManager().callEvent(prePartyEvent) 189 | 190 | if (prePartyEvent.isCancelled) { 191 | return 192 | } 193 | 194 | runPrePartyCommands() 195 | 196 | plugin.runTaskLater(party.conf().getProperty(PartySettings.START_DELAY) * 20L) 197 | { 198 | 199 | val partyStartEvent = PartyStartEvent() 200 | Bukkit.getPluginManager().callEvent(partyStartEvent) 201 | 202 | if (partyStartEvent.isCancelled) { 203 | return@runTaskLater 204 | } 205 | 206 | addParties(System.currentTimeMillis()) 207 | runPartyCommands() 208 | runPartyStartEffects() 209 | 210 | val targets: Collection = when(party.conf().getProperty(PartySettings.PARTY_MODE)) { 211 | "everyone" -> server.onlinePlayers 212 | "daily" -> server.onlinePlayers.filter { party.usersHandler.getPlayersWhoVotedSince(1, TimeUnit.DAYS).contains(it.uniqueId) } 213 | "party" -> server.onlinePlayers.filter { voted.contains(it.uniqueId) } 214 | else -> server.onlinePlayers 215 | } 216 | 217 | server.onlinePlayers.filterNot { it in targets }.forEach { 218 | sendMessage(party.manager().getCommandIssuer(it), Messages.PARTY__REQUIREMENTS_NOT_MET) 219 | } 220 | 221 | if (party.conf().getProperty(PartySettings.USE_CRATE)) { 222 | val disabledWorlds = party.conf().getProperty(PartySettings.DISABLED_WORLDS) 223 | targets.filterNot { it.world.name in disabledWorlds }.forEach { 224 | it.inventory.addItem(buildCrate(1)) 225 | } 226 | } 227 | else { 228 | targets.forEach() 229 | { 230 | giveGuaranteedPartyRewards(it) 231 | giveRandomPartyRewards(it) 232 | givePermissionPartyRewards(it) 233 | } 234 | } 235 | 236 | voted.clear() 237 | val partyEndEvent = PartyEndEvent() 238 | Bukkit.getPluginManager().callEvent(partyEndEvent) 239 | 240 | runPostPartyCommands() 241 | } 242 | } 243 | 244 | 245 | private fun executeCommands(enabled: Boolean, cmds: Collection?, player: Player? = null) 246 | { 247 | if (!enabled || (player != null && (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)))) 248 | { 249 | return 250 | } 251 | 252 | cmds?.forEach() 253 | { 254 | server.dispatchCommand(server.consoleSender, if (player == null) it else formMessage(player, it)) 255 | } 256 | } 257 | 258 | 259 | private fun executeEffects(enabled: Boolean, effects: Collection, players: Collection, offsetX: Double, offsetY: Double, offsetZ: Double, speed: Double, count: Int) 260 | { 261 | if (!enabled) 262 | { 263 | return 264 | } 265 | 266 | val targets = players.filter() 267 | { 268 | it.world.name !in party.conf().getProperty(PartySettings.DISABLED_WORLDS) 269 | } 270 | 271 | effects.forEach() 272 | { effect -> 273 | targets.forEach() 274 | { player -> 275 | party.hook().display(EffectType.valueOf(effect), player.location, offsetX, offsetY, offsetZ, speed, count) 276 | } 277 | } 278 | } 279 | 280 | } 281 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/handler/VotesHandler.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.handler 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | import me.clip.voteparty.conf.sections.EffectsSettings 6 | import me.clip.voteparty.conf.sections.PartySettings 7 | import me.clip.voteparty.conf.sections.VoteData 8 | import me.clip.voteparty.conf.sections.VoteSettings 9 | import me.clip.voteparty.exte.formMessage 10 | import me.clip.voteparty.exte.sendMessage 11 | import me.clip.voteparty.exte.takeRandomly 12 | import me.clip.voteparty.leaderboard.LeaderboardType 13 | import me.clip.voteparty.messages.Messages 14 | import me.clip.voteparty.plugin.VotePartyPlugin 15 | import me.clip.voteparty.version.EffectType 16 | import org.bukkit.Bukkit 17 | import org.bukkit.entity.Player 18 | import java.util.concurrent.TimeUnit 19 | import java.util.concurrent.atomic.AtomicInteger 20 | 21 | class VotesHandler(override val plugin: VotePartyPlugin) : Addon, State 22 | { 23 | 24 | private val votes = AtomicInteger() 25 | 26 | 27 | override fun load() 28 | { 29 | votes.set(party.voteData().getProperty(VoteData.COUNTER)) 30 | } 31 | 32 | override fun kill() 33 | { 34 | votes.set(0) 35 | } 36 | 37 | 38 | fun getVotes(): Int 39 | { 40 | return votes.get() 41 | } 42 | 43 | fun setVotes(amount: Int) 44 | { 45 | votes.set(amount) 46 | } 47 | 48 | fun addVotes(amount: Int) 49 | { 50 | if (votes.addAndGet(amount) < party.conf().getProperty(PartySettings.VOTES_NEEDED)) 51 | { 52 | return 53 | } 54 | 55 | votes.set(0) 56 | party.partyHandler.startParty() 57 | } 58 | 59 | fun runAll(player: Player) 60 | { 61 | giveRandomVoteRewards(player) 62 | giveGuaranteedVoteRewards(player) 63 | givePermissionVoteRewards(player) 64 | } 65 | 66 | 67 | fun giveGuaranteedVoteRewards(player: Player) 68 | { 69 | val settings = party.conf().getProperty(VoteSettings.GUARANTEED_REWARDS) 70 | 71 | if (!settings.enabled || settings.commands.isEmpty()) 72 | { 73 | return 74 | } 75 | 76 | settings.commands.forEach() 77 | { command -> 78 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 79 | } 80 | } 81 | 82 | fun givePermissionVoteRewards(player: Player) 83 | { 84 | val settings = party.conf().getProperty(VoteSettings.PERMISSION_VOTE_REWARDS) 85 | 86 | if (!settings.enabled || settings.permCommands.isEmpty()) 87 | { 88 | return 89 | } 90 | 91 | settings.permCommands.filter { player.hasPermission(it.permission) }.forEach() 92 | { perm -> 93 | perm.commands.forEach() 94 | { command -> 95 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 96 | } 97 | } 98 | } 99 | 100 | fun checkDailyCumulative(player: Player) 101 | { 102 | val settings = party.conf().getProperty(VoteSettings.CUMULATIVE_VOTE_REWARDS) 103 | 104 | if (!settings.daily.enabled || settings.daily.entries.isEmpty()) 105 | { 106 | return 107 | } 108 | 109 | settings.daily.entries.filter { entry -> entry.votes == party.usersHandler.getVoteCountSince(player, LeaderboardType.DAILY.start.invoke()) }.forEach { entry -> 110 | entry.commands.forEach() 111 | { command -> 112 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 113 | } 114 | } 115 | } 116 | 117 | fun checkWeeklyCumulative(player: Player) 118 | { 119 | val settings = party.conf().getProperty(VoteSettings.CUMULATIVE_VOTE_REWARDS) 120 | 121 | if (!settings.weekly.enabled || settings.weekly.entries.isEmpty()) 122 | { 123 | return 124 | } 125 | 126 | settings.weekly.entries.filter { entry -> entry.votes == party.usersHandler.getVoteCountSince(player, LeaderboardType.WEEKLY.start.invoke()) }.forEach { entry -> 127 | entry.commands.forEach() 128 | { command -> 129 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 130 | } 131 | } 132 | } 133 | 134 | fun checkMonthlyCumulative(player: Player) 135 | { 136 | val settings = party.conf().getProperty(VoteSettings.CUMULATIVE_VOTE_REWARDS) 137 | 138 | if (!settings.monthly.enabled || settings.monthly.entries.isEmpty()) 139 | { 140 | return 141 | } 142 | 143 | settings.monthly.entries.filter { entry -> entry.votes == party.usersHandler.getVoteCountSince(player, LeaderboardType.MONTHLY.start.invoke()) }.forEach { entry -> 144 | entry.commands.forEach() 145 | { command -> 146 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 147 | } 148 | } 149 | } 150 | 151 | fun checkYearlyCumulative(player: Player) 152 | { 153 | val settings = party.conf().getProperty(VoteSettings.CUMULATIVE_VOTE_REWARDS) 154 | 155 | if (!settings.yearly.enabled || settings.yearly.entries.isEmpty()) 156 | { 157 | return 158 | } 159 | 160 | settings.yearly.entries.filter { entry -> entry.votes == party.usersHandler.getVoteCountSince(player, LeaderboardType.ANNUALLY.start.invoke()) }.forEach { entry -> 161 | entry.commands.forEach() 162 | { command -> 163 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 164 | } 165 | } 166 | } 167 | 168 | fun checkTotalCumulative(player: Player) 169 | { 170 | val settings = party.conf().getProperty(VoteSettings.CUMULATIVE_VOTE_REWARDS) 171 | 172 | if (!settings.total.enabled || settings.total.entries.isEmpty()) 173 | { 174 | return 175 | } 176 | 177 | settings.total.entries.filter { entry -> entry.votes == party.usersHandler.getVoteCountSince(player, LeaderboardType.ALLTIME.start.invoke()) }.forEach { entry -> 178 | entry.commands.forEach() 179 | { command -> 180 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 181 | } 182 | } 183 | } 184 | 185 | fun giveVotesiteVoteRewards(player: Player, serviceName: String) 186 | { 187 | val settings = party.conf().getProperty(VoteSettings.VOTESITE_VOTE_REWARDS) 188 | 189 | if (!settings.enabled || settings.votesiteCommands.isEmpty()) 190 | { 191 | return 192 | } 193 | 194 | val first = settings.votesiteCommands.firstOrNull { serviceName == it.serviceName } 195 | 196 | first?.commands?.forEach() 197 | { 198 | server.dispatchCommand(server.consoleSender, formMessage(player, it)) 199 | } 200 | } 201 | 202 | fun giveFirstTimeVoteRewards(player: Player) 203 | { 204 | val settings = party.conf().getProperty(VoteSettings.FIRST_TIME_REWARDS) 205 | 206 | if (!settings.enabled || settings.commands.isEmpty()) 207 | { 208 | return 209 | } 210 | 211 | settings.commands.forEach() 212 | { command -> 213 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 214 | } 215 | } 216 | 217 | fun giveRandomVoteRewards(player: Player) 218 | { 219 | val settings = party.conf().getProperty(VoteSettings.PER_VOTE_REWARDS) 220 | 221 | if (!settings.enabled || settings.max_possible <= 0 || settings.commands.isEmpty()) 222 | { 223 | return 224 | } 225 | 226 | settings.commands.takeRandomly(settings.max_possible).forEach() 227 | { section -> 228 | section.command.forEach() 229 | { command -> 230 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 231 | } 232 | } 233 | } 234 | 235 | fun playerVoteEffects(player: Player) 236 | { 237 | val settings = party.conf().getProperty(EffectsSettings.VOTE) 238 | 239 | if (!settings.enable || settings.effects.isEmpty()) 240 | { 241 | return 242 | } 243 | 244 | val location = player.location 245 | 246 | settings.effects.forEach { 247 | party.hook().display(EffectType.valueOf(it), location, settings.offsetX, settings.offsetY, settings.offsetZ, settings.speed, settings.count) 248 | } 249 | } 250 | 251 | fun runGlobalCommands(player: Player) 252 | { 253 | val settings = party.conf().getProperty(VoteSettings.GLOBAL_COMMANDS) 254 | 255 | if (!settings.enabled || settings.commands.isEmpty()) 256 | { 257 | return 258 | } 259 | 260 | settings.commands.forEach() 261 | { command -> 262 | server.dispatchCommand(server.consoleSender, formMessage(player, command)) 263 | } 264 | } 265 | 266 | fun sendVoteReminders() 267 | { 268 | val players = Bukkit.getOnlinePlayers().filter { 269 | party.usersHandler.getVoteCountSince( 270 | it, 271 | party.conf().getProperty(VoteSettings.REMINDER_INTERVAL).toLong(), 272 | TimeUnit.HOURS 273 | ) < party.conf().getProperty(VoteSettings.REMINDER_THRESHOLD) 274 | } 275 | 276 | players.forEach { 277 | sendMessage(party.manager().getCommandIssuer(it), Messages.VOTES__REMINDER) 278 | } 279 | } 280 | 281 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/leaderboard/Leaderboard.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.leaderboard 2 | 3 | import me.clip.voteparty.user.User 4 | 5 | data class Leaderboard(val type: LeaderboardType, val data: List) 6 | { 7 | fun getEntry(entry: Int) : LeaderboardUser? 8 | { 9 | return data.getOrNull((entry - 1).coerceAtLeast(0)) 10 | } 11 | 12 | private fun getUser(user: User) : LeaderboardUser? 13 | { 14 | return data.firstOrNull{ user.name == it.name() } 15 | } 16 | 17 | fun getPlacement(user: User) : Int? 18 | { 19 | return data.indexOfFirst { getUser(user) == it } 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/leaderboard/LeaderboardType.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.leaderboard 2 | 3 | import java.time.LocalDate 4 | import java.time.LocalDateTime 5 | import java.time.temporal.ChronoField 6 | 7 | enum class LeaderboardType(val start: () -> LocalDateTime, val end: () -> LocalDateTime, val displayName: String) { 8 | DAILY( 9 | { LocalDate.now().atStartOfDay() }, 10 | { LocalDateTime.MIN }, 11 | "Daily" 12 | ), 13 | WEEKLY( 14 | { LocalDate.now().with(ChronoField.DAY_OF_WEEK, 1).atStartOfDay() }, 15 | { LocalDateTime.MIN }, 16 | "Weekly" 17 | ), 18 | LASTMONTH( 19 | { LocalDate.now().minusMonths(1).with(ChronoField.DAY_OF_MONTH, 1).atStartOfDay() }, 20 | { LocalDate.now().with(ChronoField.DAY_OF_MONTH, 1).atStartOfDay() }, 21 | "Last Month" 22 | ), 23 | MONTHLY( 24 | { LocalDate.now().with(ChronoField.DAY_OF_MONTH, 1).atStartOfDay() }, 25 | { LocalDateTime.MIN }, 26 | "Monthly" 27 | ), 28 | ANNUALLY( 29 | { LocalDate.now().with(ChronoField.DAY_OF_YEAR, 1).atStartOfDay() }, 30 | { LocalDateTime.MIN }, 31 | "Annually" 32 | ), 33 | ALLTIME( 34 | { LocalDate.now().with(ChronoField.EPOCH_DAY, 1).atStartOfDay() }, 35 | { LocalDateTime.MIN }, 36 | "All Time" 37 | ); 38 | 39 | companion object 40 | { 41 | internal val values = values() 42 | 43 | internal fun find(name: String): LeaderboardType? 44 | { 45 | return values.find { it.name.equals(name, true) } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/leaderboard/LeaderboardUser.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.leaderboard 2 | 3 | import me.clip.voteparty.user.User 4 | 5 | data class LeaderboardUser(val user: User, var votes: Int) 6 | { 7 | fun name() : String 8 | { 9 | return user.name 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/listener/CrateListener.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.listener 2 | 3 | import me.clip.voteparty.conf.sections.CrateSettings 4 | import me.clip.voteparty.conf.sections.PartySettings 5 | import me.clip.voteparty.listener.base.VotePartyListener 6 | import me.clip.voteparty.plugin.VotePartyPlugin 7 | import org.bukkit.event.EventHandler 8 | import org.bukkit.event.block.Action 9 | import org.bukkit.event.player.PlayerInteractEvent 10 | 11 | internal class CrateListener(override val plugin: VotePartyPlugin) : VotePartyListener 12 | { 13 | 14 | @EventHandler 15 | fun PlayerInteractEvent.onInteract() 16 | { 17 | if (party.conf().getProperty(CrateSettings.ENABLED) == false) 18 | { 19 | return 20 | } 21 | 22 | if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) 23 | { 24 | return 25 | } 26 | 27 | val held = player.inventory.itemInHand 28 | val item = party.partyHandler.buildCrate(1) 29 | 30 | if (!held.isSimilar(item)) 31 | { 32 | return 33 | } 34 | 35 | if (player.world.name in party.conf().getProperty(PartySettings.DISABLED_WORLDS)) 36 | { 37 | return 38 | } 39 | 40 | isCancelled = true 41 | 42 | if (held.amount == 1) 43 | { 44 | player.inventory.removeItem(held) 45 | } 46 | else 47 | { 48 | player.inventory.itemInHand.amount = held.amount - 1 49 | } 50 | 51 | party.partyHandler.runAll(player) 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/listener/HooksListenerNuVotifier.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.listener 2 | 3 | import com.vexsoftware.votifier.model.VotifierEvent 4 | import me.clip.voteparty.conf.sections.VoteSettings 5 | import me.clip.voteparty.events.VoteReceivedEvent 6 | import me.clip.voteparty.listener.base.VotePartyListener 7 | import me.clip.voteparty.plugin.VotePartyPlugin 8 | import org.bukkit.event.EventHandler 9 | import java.util.regex.Pattern 10 | 11 | internal class HooksListenerNuVotifier(override val plugin: VotePartyPlugin) : VotePartyListener 12 | { 13 | private lateinit var usernameRegex: Pattern 14 | override fun load() { 15 | super.load() 16 | usernameRegex = Pattern.compile(party.conf().getProperty(VoteSettings.NAME_REGEX)) 17 | } 18 | 19 | @EventHandler 20 | fun VotifierEvent.onVote() 21 | { 22 | if (vote == null || vote.username.isNullOrEmpty()) { 23 | plugin.logger.warning("A vote come through NuVotifier which was null or did not provide a username. Throwing away.") 24 | return 25 | } 26 | 27 | if (party.conf().getProperty(VoteSettings.VALIDATE_NAMES) && !usernameRegex.matcher(vote.username).matches()) { 28 | plugin.logger.warning("A vote came through NuVotifier (username: ${vote.username}) which did not match the username regex. Throwing away.") 29 | return 30 | } 31 | 32 | // Try pulling the username from the user cache first before querying Bukkit / Mojang 33 | val player = party.usersHandler[vote.username]?.player() ?: server.getOfflinePlayer(vote.username) 34 | val event = VoteReceivedEvent(player, vote.serviceName) 35 | server.pluginManager.callEvent(event) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/listener/VotesListener.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.listener 2 | 3 | import me.clip.voteparty.conf.sections.PartySettings 4 | import me.clip.voteparty.conf.sections.PluginSettings 5 | import me.clip.voteparty.conf.sections.VoteSettings 6 | import me.clip.voteparty.events.VoteReceivedEvent 7 | import me.clip.voteparty.exte.runTaskLater 8 | import me.clip.voteparty.exte.sendMessage 9 | import me.clip.voteparty.listener.base.VotePartyListener 10 | import me.clip.voteparty.messages.Messages 11 | import me.clip.voteparty.plugin.VotePartyPlugin 12 | import org.bukkit.event.EventHandler 13 | import org.bukkit.event.EventPriority 14 | import org.bukkit.event.player.PlayerJoinEvent 15 | 16 | internal class VotesListener(override val plugin: VotePartyPlugin) : VotePartyListener 17 | { 18 | 19 | @EventHandler 20 | fun VoteReceivedEvent.onReceive() 21 | { 22 | 23 | var first = false 24 | 25 | val user = party.usersHandler[player] 26 | if (!user.hasVotedBefore()) 27 | { 28 | first = true 29 | } 30 | user.voted() 31 | 32 | if (!player.isOnline && party.conf().getProperty(VoteSettings.OFFLINE_VOTE_CLAIMING)) 33 | { 34 | user.claimable++ 35 | } 36 | 37 | if (party.conf().getProperty(PluginSettings.SAVE_ON_VOTE)) 38 | { 39 | party.usersHandler.save(user) 40 | } 41 | 42 | if (!player.isOnline && !party.conf().getProperty(PartySettings.OFFLINE_VOTES)) 43 | { 44 | return 45 | } 46 | 47 | if ((party.conf().getProperty(PartySettings.PARTY_MODE) == "party") && !party.partyHandler.voted.contains(user.uuid)) { 48 | party.partyHandler.voted.add(user.uuid) 49 | } 50 | 51 | party.votesHandler.addVotes(1) 52 | 53 | val online = player.player ?: return 54 | 55 | 56 | if (online.inventory.firstEmpty() == -1 && party.conf().getProperty(VoteSettings.CLAIMABLE_IF_FULL)) 57 | { 58 | user.claimable++ 59 | return sendMessage(party.manager().getCommandIssuer(online), Messages.VOTES__INVENTORY_FULL) 60 | } 61 | 62 | party.votesHandler.runGlobalCommands(online) 63 | party.votesHandler.runAll(online) 64 | 65 | if (vote != "") 66 | { 67 | party.votesHandler.giveVotesiteVoteRewards(online, vote) 68 | } 69 | 70 | if (first) 71 | { 72 | party.votesHandler.giveFirstTimeVoteRewards(online) 73 | } 74 | 75 | party.votesHandler.checkDailyCumulative(online) 76 | party.votesHandler.checkWeeklyCumulative(online) 77 | party.votesHandler.checkMonthlyCumulative(online) 78 | party.votesHandler.checkYearlyCumulative(online) 79 | party.votesHandler.checkTotalCumulative(online) 80 | 81 | party.votesHandler.playerVoteEffects(online) 82 | } 83 | 84 | @EventHandler(priority = EventPriority.HIGH) 85 | fun PlayerJoinEvent.onJoin() 86 | { 87 | if (!player.hasPlayedBefore()) 88 | { 89 | return 90 | } 91 | 92 | if (party.usersHandler[player].claimable > 0 && party.conf().getProperty(VoteSettings.OFFLINE_VOTE_CLAIMING_NOTIFY)) 93 | { 94 | plugin.runTaskLater(40L) 95 | { 96 | sendMessage(party.manager().getCommandIssuer(player), Messages.CLAIM__NOTIFY) 97 | } 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/listener/base/VotePartyListener.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.listener.base 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | import org.bukkit.event.HandlerList 6 | import org.bukkit.event.Listener 7 | 8 | internal interface VotePartyListener : Addon, State, Listener 9 | { 10 | 11 | override fun load() 12 | { 13 | server.pluginManager.registerEvents(this, plugin) 14 | } 15 | 16 | override fun kill() 17 | { 18 | HandlerList.unregisterAll(this) 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/messages/Messages.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.messages 2 | 3 | import co.aikar.locales.MessageKey 4 | import co.aikar.locales.MessageKeyProvider 5 | import java.util.* 6 | 7 | enum class Messages : MessageKeyProvider 8 | { 9 | 10 | ERROR__LEADERBOARD_NOT_FOUND, 11 | ERROR__INVALID_PAGE_NUMBER, 12 | ERROR__INVALID_NUMBER, 13 | ERROR__DISABLED_WORLD, 14 | ERROR__USER_NOT_FOUND, 15 | 16 | INFO__VOTES_NEEDED, 17 | INFO__RELOADED, 18 | INFO__VOTE_COUNT_RESET, 19 | INFO__PLAYER_TOTAL_VOTES, 20 | INFO__PLAYER_CHECK_VOTES, 21 | 22 | PARTY__FORCE_START_SUCCESSFUL, 23 | PARTY__REQUIREMENTS_NOT_MET, 24 | 25 | VOTES__VOTES_NEEDED_UPDATED, 26 | VOTES__VOTE_COUNTER_UPDATED, 27 | VOTES__PRIVATE_PARTY_GIVEN, 28 | VOTES__PRIVATE_PARTY_RECEIVED, 29 | VOTES__ADDED_TO_PLAYER, 30 | VOTES__INVENTORY_FULL, 31 | VOTES__REMINDER, 32 | 33 | CRATE__CRATE_GIVEN, 34 | CRATE__CRATE_RECEIVED, 35 | 36 | CLAIM__SUCCESS, 37 | CLAIM__SUCCESS_ALL, 38 | CLAIM__NONE, 39 | CLAIM__NOTIFY, 40 | CLAIM__FULL, 41 | CLAIM__FULL_ALL, 42 | 43 | DESCRIPTIONS__HELP, 44 | DESCRIPTIONS__SETCOUNTER, 45 | DESCRIPTIONS__ADDVOTE, 46 | DESCRIPTIONS__STARTPARTY, 47 | DESCRIPTIONS__TOP, 48 | DESCRIPTIONS__ADDPARTYVOTE, 49 | DESCRIPTIONS__GIVECRATE, 50 | DESCRIPTIONS__GIVEPARTY, 51 | DESCRIPTIONS__RELOAD, 52 | DESCRIPTIONS__CHECKVOTES, 53 | DESCRIPTIONS__TOTALVOTES, 54 | DESCRIPTIONS__RESETVOTES, 55 | DESCRIPTIONS__CLAIM, 56 | DESCRIPTIONS__CLAIMALL, 57 | 58 | TOP__HEADER, 59 | TOP__LINE, 60 | TOP__FOOTER, 61 | 62 | HELP__HEADER, 63 | HELP__LINE_TEXT, 64 | HELP__LINE_HOVER, 65 | HELP__FOOTER; 66 | 67 | 68 | private val key = MessageKey.of(name.lowercase(Locale.getDefault()).replace("__", ".").replace('_', '-')) 69 | 70 | override fun getMessageKey(): MessageKey 71 | { 72 | return key 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/placeholders/VotePartyPlaceholders.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.placeholders 2 | 3 | import me.clip.placeholderapi.expansion.PlaceholderExpansion 4 | import me.clip.voteparty.VoteParty 5 | import me.clip.voteparty.leaderboard.LeaderboardType 6 | import org.bukkit.OfflinePlayer 7 | import java.util.* 8 | 9 | class VotePartyPlaceholders(private val voteParty: VoteParty) : PlaceholderExpansion() 10 | { 11 | 12 | override fun getAuthor(): String 13 | { 14 | return "Glare" 15 | } 16 | 17 | override fun getVersion(): String 18 | { 19 | return "2.0" 20 | } 21 | 22 | override fun getIdentifier(): String 23 | { 24 | return "voteparty" 25 | } 26 | 27 | override fun persist(): Boolean 28 | { 29 | return true 30 | } 31 | 32 | 33 | override fun onRequest(player: OfflinePlayer?, arg: String): String { 34 | if (arg.startsWith("top_")) { 35 | return getTop(arg.replace("top_", "").lowercase(Locale.getDefault())) 36 | } 37 | 38 | if (arg.startsWith("placement_")) { 39 | return getPlacement(arg.replace("placement_", "").lowercase(Locale.getDefault()), player ?: return "") 40 | } 41 | 42 | if (arg.startsWith("totalvotes_")) { 43 | return getVotes(arg.replace("totalvotes_", "").lowercase(Locale.getDefault()), player ?: return "") 44 | } 45 | 46 | if (arg.startsWith("totalparties_")) { 47 | return getParties(arg.replace("totalparties_", "").lowercase(Locale.getDefault())) 48 | } 49 | 50 | return when (arg.lowercase(Locale.getDefault())) { 51 | "votes_recorded" -> voteParty.getVotes().toString() 52 | "votes_required_party" -> voteParty.getVotesNeeded().minus(voteParty.getVotes()).toString() 53 | "votes_required_total" -> voteParty.getVotesNeeded().toString() 54 | "votes_total" -> voteParty.usersHandler.getTotalVotes().toString() 55 | "player_votes" -> voteParty.usersHandler[player ?: return ""].votes().size.toString() 56 | else -> "" 57 | } 58 | } 59 | 60 | /** 61 | * Get the "top" data for a leaderboard 62 | */ 63 | private fun getTop(input: String): String 64 | { 65 | val (type, info, placement) = input.split('_').takeIf { it.size >= 3 } ?: return "" 66 | 67 | // Get the leaderboard type but return empty if invalid type 68 | val leaderboard = LeaderboardType.find(type)?.let(voteParty.leaderboardHandler::getLeaderboard) ?: return "" 69 | 70 | // Get the user if the placeholder isn't null 71 | val user = placement.toIntOrNull()?.let(leaderboard::getEntry) ?: return "" 72 | 73 | // Return the correct data 74 | return when (info) 75 | { 76 | "name" -> user.name() 77 | "votes" -> user.votes.toString() 78 | else -> "" 79 | } 80 | } 81 | 82 | /** 83 | * Get the placement of a player based on the given leaderboard type 84 | */ 85 | private fun getPlacement(input: String, player: OfflinePlayer): String 86 | { 87 | val leaderboard = LeaderboardType.find(input)?.let(voteParty.leaderboardHandler::getLeaderboard) ?: return "" 88 | 89 | return leaderboard.getPlacement(voteParty.usersHandler[player])?.plus(1)?.toString() ?: "" 90 | } 91 | 92 | /** 93 | * Get the amount of votes a player has based on the given leaderboard type 94 | */ 95 | private fun getVotes(input: String, player: OfflinePlayer): String 96 | { 97 | return LeaderboardType.find(input)?.let { 98 | voteParty.usersHandler.getVoteCountWithinRange(player, it.start.invoke(), it.end.invoke()) 99 | }?.toString() ?: "" 100 | } 101 | 102 | /** 103 | * Get the amount of parties that have been triggered based on the given leaderboard type 104 | */ 105 | private fun getParties(input: String): String 106 | { 107 | return LeaderboardType.find(input)?.let { voteParty.partyHandler.getPartiesSince(it.start.invoke()) }?.toString() ?: "" 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/user/User.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.user 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.OfflinePlayer 5 | import java.util.UUID 6 | 7 | data class User(val uuid: UUID, var name: String, private val data: MutableList, var claimable: Int) 8 | { 9 | 10 | fun voted() 11 | { 12 | data += System.currentTimeMillis() 13 | } 14 | 15 | fun votes(): List 16 | { 17 | return data 18 | } 19 | 20 | fun hasVotedBefore(): Boolean 21 | { 22 | return data.isNotEmpty() 23 | } 24 | 25 | fun reset() 26 | { 27 | data.clear() 28 | } 29 | 30 | fun player() : OfflinePlayer 31 | { 32 | return Bukkit.getOfflinePlayer(uuid) 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/user/UsersHandler.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.user 2 | 3 | import me.clip.voteparty.base.Addon 4 | import me.clip.voteparty.base.State 5 | import me.clip.voteparty.data.impl.DatabaseVotePlayerGson 6 | import me.clip.voteparty.leaderboard.LeaderboardUser 7 | import me.clip.voteparty.plugin.VotePartyPlugin 8 | import org.bukkit.OfflinePlayer 9 | import org.bukkit.event.EventHandler 10 | import org.bukkit.event.HandlerList 11 | import org.bukkit.event.Listener 12 | import org.bukkit.event.player.PlayerJoinEvent 13 | import java.time.Instant 14 | import java.time.LocalDateTime 15 | import java.time.ZoneId 16 | import java.util.* 17 | import java.util.concurrent.TimeUnit 18 | 19 | /** 20 | * 21 | * And I quote. "Wait till someone complains" - Glare 2020 22 | * 23 | */ 24 | class UsersHandler(override val plugin: VotePartyPlugin) : Addon, State, Listener 25 | { 26 | 27 | private val database = DatabaseVotePlayerGson(plugin) 28 | private val cached = mutableMapOf() 29 | 30 | 31 | override fun load() 32 | { 33 | database.load() 34 | 35 | database.load(emptyList()).forEach() 36 | { (_, data) -> 37 | data ?: return@forEach 38 | 39 | cached[data.uuid] = data 40 | cached[data.name.lowercase(Locale.getDefault())] = data 41 | } 42 | server.pluginManager.registerEvents(this, plugin) 43 | } 44 | 45 | override fun kill() 46 | { 47 | saveAll() 48 | database.kill() 49 | 50 | cached.clear() 51 | 52 | HandlerList.unregisterAll(this) 53 | } 54 | 55 | 56 | operator fun get(uuid: UUID): User 57 | { 58 | return cached.getOrPut(uuid) 59 | { 60 | User(uuid, "", mutableListOf(), 0) 61 | } 62 | } 63 | 64 | operator fun get(name: String): User? 65 | { 66 | return cached[name.lowercase(Locale.getDefault())] 67 | } 68 | 69 | operator fun get(player: OfflinePlayer): User 70 | { 71 | return get(player.uniqueId) 72 | } 73 | 74 | 75 | fun reset(player: OfflinePlayer) 76 | { 77 | get(player).reset() 78 | } 79 | 80 | fun saveAll() 81 | { 82 | database.save(cached.values.distinct()) 83 | } 84 | 85 | fun save(user: User) 86 | { 87 | database.save(user) 88 | } 89 | 90 | /** 91 | * Get the amount of votes a player has made since the given time. 92 | * @param offlinePlayer The player to check. 93 | * @param amount The amount of time to check since. 94 | * @param unit The unit of time to check since. 95 | * @return The amount of votes the player has made since the given time. 96 | */ 97 | fun getVoteCountSince(offlinePlayer: OfflinePlayer, amount: Long, unit: TimeUnit): Int 98 | { 99 | val timeEpoch = Instant.now().minusMillis(TimeUnit.MILLISECONDS.convert(amount, unit)).toEpochMilli() 100 | 101 | return getVoteCountSince(offlinePlayer, timeEpoch) 102 | } 103 | 104 | /** 105 | * Get the amount of votes a player has made since the given time. 106 | * @param offlinePlayer The player to check. 107 | * @param time The time to check since. 108 | * @return The amount of votes the player has made since the given time. 109 | */ 110 | fun getVoteCountSince(offlinePlayer: OfflinePlayer, time: LocalDateTime): Int 111 | { 112 | val timeEpoch = time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 113 | 114 | return getVoteCountSince(offlinePlayer, timeEpoch) 115 | } 116 | 117 | /** 118 | * Get the amount of votes a player has made since the given time. 119 | * @param offlinePlayer The player to check. 120 | * @param epoch The epoch time to check since. 121 | * @return The amount of votes the player has made since the given time. 122 | */ 123 | fun getVoteCountSince(offlinePlayer: OfflinePlayer, epoch: Long) : Int 124 | { 125 | return get(offlinePlayer).votes().count { it >= epoch } 126 | } 127 | 128 | /** 129 | * Get the amount of votes a player has made in a range of time. 130 | * @param offlinePlayer The player to check. 131 | * @param start The start of the range. 132 | * @param end The end of the range. 133 | * @return The amount of votes the player has made in the given range. 134 | */ 135 | fun getVoteCountWithinRange(offlinePlayer: OfflinePlayer, start: LocalDateTime, end: LocalDateTime): Int 136 | { 137 | if (end < start) { 138 | return getVoteCountSince(offlinePlayer, start) 139 | } 140 | 141 | val startEpoch = start.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 142 | val endEpoch = end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 143 | 144 | return getVoteCountWithinRange(offlinePlayer, startEpoch, endEpoch) 145 | } 146 | 147 | /** 148 | * Get the amount of votes a player has made in a range of time. 149 | * @param offlinePlayer The player to check. 150 | * @param startEpoch The start of the range. 151 | * @param endEpoch The end of the range. 152 | * @return The amount of votes the player has made in the given range. 153 | */ 154 | fun getVoteCountWithinRange(offlinePlayer: OfflinePlayer, startEpoch: Long, endEpoch: Long): Int 155 | { 156 | if (endEpoch < startEpoch) { 157 | return getVoteCountSince(offlinePlayer, startEpoch) 158 | } 159 | 160 | return get(offlinePlayer).votes().count { voteEpoch -> voteEpoch in startEpoch until endEpoch } 161 | } 162 | 163 | /** 164 | * Get a list of all players who have voted since the given time. 165 | * @param amount The amount of time to check since. 166 | * @param unit The unit of time to check since. 167 | */ 168 | fun getPlayersWhoVotedSince(amount: Long, unit: TimeUnit) : List 169 | { 170 | val timeEpoch = Instant.now().minusMillis(TimeUnit.MILLISECONDS.convert(amount, unit)).toEpochMilli() 171 | 172 | return getPlayersWhoVotedSince(timeEpoch) 173 | } 174 | 175 | /** 176 | * Get a list of all players who have voted since the given time. 177 | * @param epoch The epoch time to check since. 178 | * @return A list of players who have voted since the given time. 179 | */ 180 | fun getPlayersWhoVotedSince(epoch: Long): List 181 | { 182 | return cached.values.distinct().filter { getVoteCountSince(it.player(), epoch) > 0 }.map { it.uuid } 183 | } 184 | 185 | /** 186 | * Get a list of all users who have voted within the given range with the amount of votes they have made in that range. 187 | * @param start The start of the range. 188 | * @param end The end of the range. 189 | * @return A list of users who have voted within the given range. 190 | */ 191 | fun getUsersWithVotesWithinRange(start: LocalDateTime, end: LocalDateTime): List 192 | { 193 | if (end < start) { 194 | return getUsersWithVotesSince(start) 195 | } 196 | 197 | val startEpoch = start.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 198 | val endEpoch = end.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 199 | 200 | return cached.values.asSequence() 201 | .distinct() 202 | .filter() 203 | { user -> 204 | user.votes().isNotEmpty() 205 | } 206 | .map() 207 | { user -> 208 | 209 | val votes = user.votes().count() 210 | { voteEpoch -> 211 | voteEpoch in startEpoch until endEpoch 212 | } 213 | 214 | LeaderboardUser(user, votes) 215 | } 216 | .sortedByDescending() 217 | { user -> 218 | user.votes 219 | } 220 | .toList() 221 | } 222 | 223 | /** 224 | * Get a list of all users who have voted since the given time with the amount of votes they have made since then. 225 | * @param time The time to check since. 226 | * @return A list of users who have voted since the given time. 227 | */ 228 | fun getUsersWithVotesSince(time: LocalDateTime): List 229 | { 230 | val timeEpoch = time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 231 | 232 | return getUsersWithVotesSince(timeEpoch) 233 | } 234 | 235 | /** 236 | * Get a list of all users who have voted since the given time with the amount of votes they have made since then. 237 | * @param epoch The epoch time to check since. 238 | * @return A list of users who have voted since the given time. 239 | */ 240 | fun getUsersWithVotesSince(epoch: Long) : List 241 | { 242 | return cached.values.asSequence().distinct() 243 | .filter { it.votes().isNotEmpty() } 244 | .map { user -> LeaderboardUser(user, user.votes().count { voteTime -> voteTime >= epoch }) } 245 | .sortedByDescending { it.votes } 246 | .toList() 247 | } 248 | 249 | /** 250 | * Get the total amount of votes made by all users ever. 251 | * @return The total amount of votes made by all users ever. 252 | */ 253 | fun getTotalVotes(): Int { 254 | return cached.values.distinct().sumOf { it.votes().size } 255 | } 256 | 257 | @EventHandler 258 | fun PlayerJoinEvent.onJoin() 259 | { 260 | val old = cached[player.uniqueId] 261 | 262 | if (old != null && old.name != player.name) { 263 | cached -= old.name.lowercase(Locale.getDefault()) 264 | cached[player.name.lowercase(Locale.getDefault())] = old 265 | old.name = player.name 266 | } 267 | 268 | if (old == null) 269 | { 270 | val new = User(player.uniqueId, player.name, mutableListOf(), 0) 271 | 272 | cached[new.uuid] = new 273 | cached[new.name.lowercase(Locale.getDefault())] = new 274 | } 275 | } 276 | 277 | } 278 | -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/util/JarFileWalker.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.util 2 | 3 | import java.io.InputStream 4 | import java.nio.file.FileSystems 5 | import java.nio.file.Files 6 | import java.nio.file.Path 7 | 8 | /** 9 | * Walks the "directory" inside the actual jar 10 | */ 11 | object JarFileWalker 12 | { 13 | 14 | fun walk(path: String, function: (Path, InputStream?) -> Unit) 15 | { 16 | FileSystems.newFileSystem(javaClass.getResource(path).toURI(), emptyMap()).use() 17 | { files -> 18 | Files.walk(files.getPath(path)).forEach() 19 | { path -> 20 | if (Files.isDirectory(path)) 21 | { 22 | return@forEach // do nothing if this is a directory 23 | } 24 | 25 | try 26 | { 27 | // attempt to pass the stream for this resource 28 | function.invoke(path, javaClass.classLoader.getResourceAsStream(path.toString().drop(1))) 29 | } 30 | catch (ex: Exception) 31 | { 32 | // fallback to just the path 33 | function.invoke(path, null) 34 | } 35 | } 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/main/kotlin/me/clip/voteparty/util/UpdateChecker.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.util 2 | 3 | import org.bukkit.plugin.Plugin 4 | import java.net.URL 5 | 6 | object UpdateChecker 7 | { 8 | 9 | private const val API = "https://api.spigotmc.org/legacy/update.php?resource=%d" 10 | 11 | 12 | fun check(plugin: Plugin, id: Int, complete: (result: UpdateResult) -> Unit) 13 | { 14 | plugin.server.scheduler.runTaskAsynchronously(plugin, Runnable 15 | { 16 | complete.invoke(check(plugin.description.version, id)) 17 | }) 18 | } 19 | 20 | /** 21 | * runs the update check on the current thread, and returns an appropriate result 22 | */ 23 | fun check(version: String, id: Int): UpdateResult 24 | { 25 | val old = version 26 | val new = try 27 | { 28 | URL(API.format(id)).readText() 29 | } 30 | catch (ex: Exception) 31 | { 32 | return UpdateResult.EXCEPTIONS(throwable = ex) 33 | } 34 | 35 | if (old == new) 36 | { 37 | return UpdateResult.UP_TO_DATE 38 | } 39 | 40 | val oldVersion = old.split('.').mapNotNull(String::toIntOrNull) 41 | val newVersion = new.split('.').mapNotNull(String::toIntOrNull) 42 | 43 | if (newVersion.size > oldVersion.size) 44 | { 45 | return UpdateResult.NEW_UPDATE(version = new) 46 | } 47 | 48 | oldVersion.forEachIndexed() 49 | { index, value -> 50 | if (value >= newVersion[index]) 51 | { 52 | return@forEachIndexed 53 | } 54 | 55 | return UpdateResult.NEW_UPDATE(version = new) 56 | } 57 | 58 | return UpdateResult.UNRELEASED 59 | } 60 | 61 | 62 | private data class Version(val name: String?) 63 | 64 | sealed class UpdateResult 65 | { 66 | 67 | abstract val message: String 68 | 69 | 70 | object UP_TO_DATE : UpdateResult() 71 | { 72 | override val message = "Version is up to date" 73 | 74 | 75 | override fun toString(): String 76 | { 77 | return "UP_TO_DATE(${UNRELEASED.message})" 78 | } 79 | 80 | } 81 | 82 | object UNRELEASED : UpdateResult() 83 | { 84 | override val message = "You're on a newer version than latest" 85 | 86 | override fun toString(): String 87 | { 88 | return "UNRELEASED($message)" 89 | } 90 | 91 | } 92 | 93 | data class NEW_UPDATE(override val message: String = "There is an update available", val version: String) 94 | : UpdateResult() 95 | 96 | data class EXCEPTIONS(override val message: String = "Failed to check for an update", val throwable: Throwable) 97 | : UpdateResult() 98 | 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/src/main/resources/config.yml -------------------------------------------------------------------------------- /src/main/resources/languages/de-DE.yml: -------------------------------------------------------------------------------- 1 | --- 2 | descriptions: 3 | help: "Hilfreiche Befehle für VoteParty." 4 | setcounter: "Setzt den aktuellen Stimmenzähler." 5 | addvote: "Add a vote to a player with the ability to trigger or not the rewards." 6 | addpartyvote: "Add a vote to the party" 7 | startparty: "Erzwingt eine VoteParty." 8 | givecrate: "Versorge ein Player mit einem Vote." 9 | giveparty: "Führt eine Private Vote Party für einen Spieler durch." 10 | reload: "Lädt die Kon­fi­gu­ra­ti­on und die Sprach Daten erneut." 11 | checkvotes: "Checkt die Anzahl der Votes die ein Spieler hat." 12 | totalvotes: "Erhalte die Gesamtanzahl an Stimmen, die ein Spieler hat." 13 | resetvotes: "Setze die Anzahl der Stimmen zurück, die ein Spieler hat." 14 | claim: "Beanspruchen der Belohnung für Offline Votes." 15 | claimall: "Claim all rewards from offline votes at once." 16 | top: "List top voters." 17 | error: 18 | leaderboard-not-found: "&fSorry, but could not find a leaderboard of type: {type}!" 19 | invalid-page-number: "&fSorry, but this page number is invalid! Please use a number between &d1 &fand &d{max}&f!" 20 | invalid-number: "&fEntschuldige, aber diese Zahl muss positiv sein, um korrekt zu funktionieren!" 21 | disabled-world: "&fEntschuldige, aber dieser Spieler ist derzeit in einer deaktivierten Welt!" 22 | user-not-found: "&fEntschuldige, dieser Spieler konnte nicht gefunden werden!" 23 | info: 24 | votes-needed: "&d%voteparty_votes_required_party% Votes &fbenötigt für die nächste Party." 25 | reloaded: "&fDie Kon­fi­gu­ra­ti­on wurde neu geladen!" 26 | player-total-votes: "&d%player_name% &fhat &d%voteparty_player_votes% &fvote(s)!" 27 | player-check-votes: "&d%player_name% &f hat in &d{count} &fZeit der letzten &d{amount} {unit}&d &fgevotet!" 28 | vote-count-reset: "&d%player_name%&f's Stimmenanzahl wurde zurückgesetzt auf &d0&f!" 29 | party: 30 | force-start-successful: "&fDu hast eine &dVote Party gestartet &ffür alle Spieler online!" 31 | requirements-not-met: "&fSorry, but you did not meet the requirements to join this party!" 32 | votes: 33 | votes-needed-updated: "&fNeue erforderlichen Stimmen wurden gesetzt! &d%voteparty_votes_required_party% Votes &fwerden benötigt für die nächste Party." 34 | vote-counter-updated: "&fAktuell Votes wurden geupdated zu &d%voteparty_votes_recorded%&f!" 35 | private-party-given: "&fDu gibst eine Private &dVote Party &ffür &d%player_name%&f!" 36 | private-party-received: "&fDu hast eine private &dVote Party&f erhalten!" 37 | added-to-player: "&fDu hast {count} Stimmen für %player_name% gegeben!" 38 | inventory-full: "&fDein Inventar scheint voll zu sein! Wir haben deine Vote Belohnung in dein Rucksack gepackt! Mache /vp claim, sobald dein Inventar nicht voll ist!" 39 | reminder: "&fDon't forget to vote for our server!" 40 | crate: 41 | crate-given: "&fDu hast &d%player_name% &fvote bekommen oder erstellt!" 42 | crate-received: "Du hast ein Vote erstellt!" 43 | claim: 44 | success: "&fDu hast erfolgreich die Belohnungen von deiner Offline-Abstimmung abgeholt! Du hast &d{claim} &fnoch zur abzuholen." 45 | success-all: "&fYou successfully claimed the rewards for all offline votes!" 46 | none: "&fDu hast keine Belohnungen von Offline-Votes!" 47 | notify: "&fHey! Du scheinst offline abgestimmt zu haben! Du hast eine oder einige Belohnungen! Sammle sie durch die Verwendung von &d/vp claim&f &fein!" 48 | full: "&aDein Inventar ist voll! Mache platz und versuche es erneut!" 49 | full-all: "&aYour inventory is full! Make some space and try again! You have claimed &d{claimed} &aoffline rewards. You have &d{claim} &aleft to claim." 50 | top: 51 | header: "&fTop Voters - {type}" 52 | line: "&e{position}. &fUser: &d{player} &f- Votes: &d{votes}" 53 | footer: "&fPage: &d{page} &f/ &d{total}" 54 | help: 55 | header: " VoteParty Hilfe " 56 | line-text: "/vp {cmd}\n" 57 | line-hover: "{text}\n{desc}\n\n/vp {cmd} {args}\n{perm}" 58 | footer: " \nHover for more info" 59 | 60 | -------------------------------------------------------------------------------- /src/main/resources/languages/en-US.yml: -------------------------------------------------------------------------------- 1 | descriptions: 2 | help: "Helpful commands for VoteParty." 3 | setcounter: "Set the current vote counter." 4 | addvote: "Add a vote to a player with the ability to trigger or not the rewards." 5 | addpartyvote: "Add a vote to the party" 6 | startparty: "Force launch a VoteParty." 7 | givecrate: "Supply a player with a Vote crate." 8 | giveparty: "Host a private Vote Party for a player." 9 | reload: "Reload the config and language file." 10 | checkvotes: "Check the amount of votes a player has." 11 | totalvotes: "Get the total amount of votes a player has." 12 | resetvotes: "Reset the amount of votes a player has." 13 | claim: "Claim rewards from offline votes." 14 | claimall: "Claim all rewards from offline votes at once." 15 | top: "List top voters." 16 | error: 17 | leaderboard-not-found: "&fSorry, but could not find a leaderboard of type: {type}!" 18 | invalid-page-number: "&fSorry, but this page number is invalid! Please use a number between &d1 &fand &d{max}&f!" 19 | invalid-number: "&fSorry, but this number must be positive in order to work correctly!" 20 | disabled-world: "&fSorry, but this player is currently in a disabled world!" 21 | user-not-found: "&fSorry, but this player could not be found!" 22 | info: 23 | votes-needed: "&d%voteparty_votes_required_party% Votes &fneeded for the next party." 24 | reloaded: "&fThe config has been reloaded!" 25 | player-total-votes: "&d%player_name% &fhas a total of &d%voteparty_player_votes% &fvote(s)!" 26 | player-check-votes: "&d%player_name% &f has voted &d{count} &ftimes in the last &d{amount} {unit}&d!" 27 | vote-count-reset: "&d%player_name%&f's vote count has been reset to &d0&f!" 28 | party: 29 | force-start-successful: "&fYou've force started a &dVote Party &ffor all online players!" 30 | requirements-not-met: "&fSorry, but you did not meet the requirements to join this party!" 31 | votes: 32 | votes-needed-updated: "&fNew required votes has been set! &d%voteparty_votes_required_party% Votes &fneeded for the next party." 33 | vote-counter-updated: "&fCurrent votes updated to &d%voteparty_votes_recorded%&f!" 34 | private-party-given: "&fYou've given a private &dVote Party &fto &d%player_name%&f!" 35 | private-party-received: "&fYou've received a private &dVote Party&f!" 36 | added-to-player: "&fYou've given {count} votes to %player_name%!" 37 | inventory-full: "&fYour inventory seems to be full! We've put this vote in your claimables! Do /vp claim once your inventory isn't full!" 38 | reminder: "&fDon't forget to vote for our server!" 39 | crate: 40 | crate-given: "&fYou've given &d%player_name% &fvote crate(s)!" 41 | crate-received: "&fYou've received a vote crate!" 42 | claim: 43 | success: "&fYou successfully claimed the rewards from an offline vote! You have &d{claim} &fleft to claim." 44 | success-all: "&fYou successfully claimed the rewards for all offline votes!" 45 | none: "&fYou don't have any rewards to claim from offline votes!" 46 | notify: "&fHey there! You seemed to have voted while offline! You have some claiming rewards! Collect them by using &d/vp claim&f!" 47 | full: "&aYour inventory is full! Make some space and try again!" 48 | full-all: "&aYour inventory is full! Make some space and try again! You have claimed &d{claimed} &aoffline rewards. You have &d{claim} &aleft to claim." 49 | top: 50 | header: "&fTop Voters - {type}" 51 | line: "&e{position}. &fUser: &d{player} &f- Votes: &d{votes}" 52 | footer: "&fPage: &d{page} &f/ &d{total}" 53 | help: 54 | header: " VoteParty Help " 55 | line-text: "/vp {cmd}\n" 56 | line-hover: "{text}\n{desc}\n\n/vp {cmd} {args}\n{perm}" 57 | footer: " \nHover for more info" 58 | 59 | -------------------------------------------------------------------------------- /src/main/resources/languages/fr-FR.yml: -------------------------------------------------------------------------------- 1 | --- 2 | descriptions: 3 | help: "Commandes utiles pour VoteParty." 4 | setcounter: "Régler le compteur de vote actuel." 5 | addvote: "Add a vote to a player with the ability to trigger or not the rewards." 6 | addpartyvote: "Add a vote to the party" 7 | startparty: "Forcer le lancement d'un VoteParty." 8 | givecrate: "Fournir une caisse de vote à un joueur." 9 | giveparty: "Organiser un VoteParty privée pour un joueur." 10 | reload: "Rechargez le fichier de configuration." 11 | checkvotes: "Vérifiez le nombre de votes d'un joueur." 12 | totalvotes: "Obtenez le nombre total de votes d'un joueur." 13 | resetvotes: "Réinitialisez le nombre de votes d'un joueur." 14 | claim: "Réclamez les récompenses pour vos votes hors ligne." 15 | claimall: "Claim all rewards from offline votes at once." 16 | top: "List top voters." 17 | error: 18 | leaderboard-not-found: "&fSorry, but could not find a leaderboard of type: {type}!" 19 | invalid-page-number: "&fSorry, but this page number is invalid! Please use a number between &d1 &fand &d{max}&f!" 20 | invalid-number: "&fDésolé, mais ce numéro doit être positif pour fonctionner correctement !" 21 | disabled-world: "&fDésolé, mais ce joueur est actuellement dans un monde désactivé !" 22 | user-not-found: "&fDésolé, mais ce joueur est introuvable!" 23 | info: 24 | votes-needed: "&d%voteparty_votes_required_party% Votes &frequis pour la prochaine party." 25 | reloaded: "&fLa configuration a été rechargée !" 26 | player-total-votes: "&d%player_name% &fa un total de &d%voteparty_player_votes% &fvote(s)!" 27 | player-check-votes: "&d%player_name% &f a voté &d{count} &ffois dans le dernier &d{amount} {unit}&d!" 28 | vote-count-reset: "&d%player_name%&f le décompte des votes a été réinitialisé à &d0&f!" 29 | party: 30 | force-start-successful: "&fVous avez lancé de force un &dVote Party &fpour tous les joueurs en ligne !" 31 | requirements-not-met: "&fSorry, but you did not meet the requirements to join this party!" 32 | votes: 33 | votes-needed-updated: "&fDe nouveaux votes obligatoires ont été fixés ! &d%voteparty_votes_required_party% Vote Party &fpour tous les joueurs en ligne." 34 | vote-counter-updated: "&fVotes actuels mis à jour à &d%voteparty_votes_recorded%&f!" 35 | private-party-given: "&f Vous avex donne des &dcaisse de votes &fa %player_name%&f!" 36 | private-party-received: "&fVous avez reçu un &dVote Party&f!" 37 | added-to-player: "&fVous avez donné {count} votes à %player_name%!" 38 | inventory-full: "&fYour inventory seems to be full! We've put this vote in your claimables! Do /vp claim once your inventory isn't full!" 39 | reminder: "&fDon't forget to vote for our server!" 40 | crate: 41 | crate-given: "&fVous avez donné à &d%player_name% &f une vote crate(s)!" 42 | crate-received: "&fVous avez reçu une caisse de vote !" 43 | claim: 44 | success: "&fVous avez réclamé les récompenses pour un vote hors ligne ! Il vous reste &d{claim} &fà récupérer." 45 | success-all: "&fYou successfully claimed the rewards for all offline votes!" 46 | none: "&fVous n'avez aucune récompense à réclamer pour des votes hors ligne !" 47 | notify: "&fHé là! Vous semblez avoir voté pendant que vous étiez hors ligne! Vous pouvez réclamer des récompenses! Collectez-les avec &d/vp claim&f!" 48 | full: "&aYour inventory is full! Make some space and try again!" 49 | full-all: "&aYour inventory is full! Make some space and try again! You have claimed &d{claimed} &aoffline rewards. You have &d{claim} &aleft to claim." 50 | top: 51 | header: "&fTop Voters - {type}" 52 | line: "&e{position}. &fUser: &d{player} &f- Votes: &d{votes}" 53 | footer: "&fPage: &d{page} &f/ &d{total}" 54 | help: 55 | header: " VoteParty Help " 56 | line-text: "/vp {cmd}\n" 57 | line-hover: "{text}\n{desc}\n\n/vp {cmd} {args}\n{perm}" 58 | footer: " \nHover for more info" 59 | 60 | -------------------------------------------------------------------------------- /src/main/resources/languages/nl-NL.yml: -------------------------------------------------------------------------------- 1 | --- 2 | descriptions: 3 | help: "Behulpzame commands voor VoteParty." 4 | setcounter: "Stel de huidige stem teller in." 5 | addvote: "Add a vote to a player with the ability to trigger or not the rewards." 6 | addpartyvote: "Add a vote to the party" 7 | startparty: "Forceer het starten van een VoteParty." 8 | givecrate: "Voorzie een speler van een Vote crate." 9 | giveparty: "Organiseer een privé Vote Party voor een speler." 10 | reload: "Herlaad het configuratie- en taalbestand." 11 | checkvotes: "Controleer de hoeveelheid stemmen die een speler heeft." 12 | totalvotes: "Haal het totale aantal stemmen op die een speler heeft." 13 | resetvotes: "Reset het aantal stemmen dat een speler heeft." 14 | claim: "Claim beloningen bij offline stemmen." 15 | claimall: "Claim all rewards from offline votes at once." 16 | top: "List top voters." 17 | error: 18 | leaderboard-not-found: "&fSorry, but could not find a leaderboard of type: {type}!" 19 | invalid-page-number: "&fSorry, but this page number is invalid! Please use a number between &d1 &fand &d{max}&f!" 20 | invalid-number: "&fSorry, maar dit nummer moet positief zijn om goed te werken!" 21 | disabled-world: "&fSorry, maar deze speler bevindt zich momenteel in een uitgeschakelde wereld!" 22 | user-not-found: "&fSorry, deze speler kon niet gevonded worden!" 23 | info: 24 | votes-needed: "&d%voteparty_votes_required_party% stemmen zijn nodig voor de volgende party." 25 | reloaded: "&fDe configuratie is herladen!" 26 | player-total-votes: "&d%player_name% &fheeft een totaal van &d%voteparty_player_votes% &fstem(men)!" 27 | player-check-votes: "&d%player_name% &f heeft &d{count} &fkeer gestemd in de laatste &d{amount} {unit}&d!" 28 | vote-count-reset: "&d%player_name%&f's aantal stemmen is gereset naar &d0&f!" 29 | party: 30 | force-start-successful: "&fJe hebt een &dVote Party &fvoor alle online spelers gestart!" 31 | requirements-not-met: "&fSorry, je voldeed niet aan de vereisten om deel te nemen aan deze VoteParty!" 32 | votes: 33 | votes-needed-updated: "&fNieuwe vereiste stemmen zijn ingesteld! &d%voteparty_votes_required_party% Stemmen &zijn nodig voor de volgende party." 34 | vote-counter-updated: "&fHuidige stemmen bijgewerkt naar &d%voteparty_votes_recorded%&f!" 35 | private-party-given: "&fJe hebt een privé &dVote Party &fgegeven aan &d%player_name%&f!" 36 | private-party-received: "&fJe hebt een privé &dVote Party&f ontvangen!" 37 | added-to-player: "&fJe hebt {count} stemmen aan %player_name% gegeven!" 38 | inventory-full: "&fJou inventaris is vol! We hebben deze stem in je claimables geplaats! Doe /vp claim wanneer je inventaris niet vol is!" 39 | reminder: "&fDon't forget to vote for our server!" 40 | crate: 41 | crate-given: "&fJe hebt &d%player_name% &fvote crate(s) gegeven!" 42 | crate-received: "&fJe hebt een vote crate ontvangen!" 43 | claim: 44 | success: "&fJe hebt succesvol de beloningen geclaimd van een offline stem! Je hebt &d{claim} &fover om te claimen." 45 | success-all: "&fYou successfully claimed the rewards for all offline votes!" 46 | none: "&fJe hebt geen beloningen die je kunt claimen van offline stemmen!" 47 | notify: "&fHey daar! Je leek te hebben gestemd terwijl je offline was! Je hebt enkele claim beloningen beschikbaar! Verzamel ze met behulp van &d/vp claim&f!" 48 | full: "&aJou inventaris is vol! Maak wat plaats en probeer opnieuw!" 49 | full-all: "&aYour inventory is full! Make some space and try again! You have claimed &d{claimed} &aoffline rewards. You have &d{claim} &aleft to claim." 50 | top: 51 | header: "&fTop Voters - {type}" 52 | line: "&e{position}. &fUser: &d{player} &f- Votes: &d{votes}" 53 | footer: "&fPage: &d{page} &f/ &d{total}" 54 | help: 55 | header: " VoteParty Hulp " 56 | line-text: "/vp {cmd}\n" 57 | line-hover: "{text}\n{desc}\n\n/vp {cmd} {args}\n{perm}" 58 | footer: " \nHover for more info" 59 | 60 | -------------------------------------------------------------------------------- /src/main/resources/languages/sv-SE.yml: -------------------------------------------------------------------------------- 1 | --- 2 | descriptions: 3 | help: "Hjälpsamma kommandon till VoteParty." 4 | setcounter: "Ange nuvarande röstantal." 5 | addvote: "Add a vote to a player with the ability to trigger or not the rewards." 6 | addpartyvote: "Add a vote to the party" 7 | startparty: "Tvångs kör ett VoteParty." 8 | givecrate: "Förse en spelare med en röstlåda." 9 | giveparty: "Aktivera ett privat Vote Party för en spelare." 10 | reload: "Ladda om konfigurations filerna." 11 | checkvotes: "Kontrollera antalet röster en spelare har." 12 | totalvotes: "Få totala antalet röster en spelare har." 13 | resetvotes: "Nollställ antalet röster en spelare har." 14 | claim: "Hämta belöningar från offline röster." 15 | claimall: "Claim all rewards from offline votes at once." 16 | top: "List top voters." 17 | error: 18 | leaderboard-not-found: "&fSorry, but could not find a leaderboard of type: {type}!" 19 | invalid-page-number: "&fSorry, but this page number is invalid! Please use a number between &d1 &fand &d{max}&f!" 20 | invalid-number: "&fTyvärr, men det måste vara ett positivt heltal för att det ska fungera korrekt!" 21 | disabled-world: "&fTyvärr, men den spelaren är i en avstängd värld!" 22 | user-not-found: "&fTyvärr, men spelaren hittades ej!" 23 | info: 24 | votes-needed: "&d%voteparty_votes_required_party% Röster &fbehövs för nästa party." 25 | reloaded: "&fKonfigurationen config har laddats om!" 26 | player-total-votes: "&d%player_name% &fhar ett totalt antal av &d%voteparty_player_votes% &fröst(er)!" 27 | player-check-votes: "&d%player_name% &fhar röstat &d{count} gånger under de senaste &d{amount} {unit}&d!" 28 | vote-count-reset: "&d%player_name%&f's röster har återställts till &d0&f!" 29 | party: 30 | force-start-successful: "&fDu tvingade igång ett &dVote Party &fför alla onlinespelare!" 31 | requirements-not-met: "&fSorry, but you did not meet the requirements to join this party!" 32 | votes: 33 | votes-needed-updated: "&fNya nödvändiga röster har ändrats! &d%voteparty_votes_required_party% Röster &fbehövda för nästa party." 34 | vote-counter-updated: "&fNuvarande röster uppdaterades till &d%voteparty_votes_recorded%&f!" 35 | private-party-given: "&fDu har skänkt ett privat &dVote Party &ftill &d%player_name%&f!" 36 | private-party-received: "&fDu har fått ett privat &dVote Party&f!" 37 | added-to-player: "&fDu har gett {count} röster till %player_name%!" 38 | inventory-full: "&fYour inventory seems to be full! We've put this vote in your claimables! Do /vp claim once your inventory isn't full!" 39 | reminder: "&fDon't forget to vote for our server!" 40 | crate: 41 | crate-given: "&fDu har gett &d%player_name% röstlådor!" 42 | crate-received: "&fDu har fått en röstlåda!" 43 | claim: 44 | success: "&fDu har lyckats hämtat belöningarna från en offlineröst! Du har &d{claim} &fkvar att hämta." 45 | success-all: "&fYou successfully claimed the rewards for all offline votes!" 46 | none: "&fDu har inga belöningar från offlineröster att hämta!" 47 | notify: "&fHej där! Du har röstat när du varit offline! Du har belöningar att hämta! Samla in dem genom kommandot &d/vp claim&f!" 48 | full: "&aYour inventory is full! Make some space and try again!" 49 | full-all: "&aYour inventory is full! Make some space and try again! You have claimed &d{claimed} &aoffline rewards. You have &d{claim} &aleft to claim." 50 | top: 51 | header: "&fTop Voters - {type}" 52 | line: "&e{position}. &fUser: &d{player} &f- Votes: &d{votes}" 53 | footer: "&fPage: &d{page} &f/ &d{total}" 54 | help: 55 | header: " VoteParty Help " 56 | line-text: "/vp {cmd}\n" 57 | line-hover: "{text}\n{desc}\n\n/vp {cmd} {args}\n{perm}" 58 | footer: " \nHover for more info" 59 | 60 | -------------------------------------------------------------------------------- /src/main/resources/parties.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/src/main/resources/parties.json -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: VoteParty 2 | main: me.clip.voteparty.plugin.VotePartyPlugin 3 | 4 | version: '@version@' 5 | website: 'https://helpch.at/discord' 6 | authors: ['Glare', 'Clip', 'Sxtanna'] 7 | 8 | depend: 9 | - 'PlaceholderAPI' 10 | softdepend: 11 | - 'Votifier' 12 | 13 | api-version: '1.13' 14 | description: 'Reward players with random commands being executed for them when the server gets x amount of votes' 15 | 16 | 17 | permissions: 18 | voteparty.command.admin: 19 | description: 'Ability to use all admin commands' 20 | default: op 21 | voteparty.command.claim: 22 | description: 'Ability to claim offline vote rewards' 23 | default: true -------------------------------------------------------------------------------- /src/main/resources/voted-for-party-cache.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/src/main/resources/voted-for-party-cache.json -------------------------------------------------------------------------------- /src/main/resources/votes.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darbyjack/VoteParty/456c4c7565bfdaa1f917c7259486126e1f0abd2c/src/main/resources/votes.yml -------------------------------------------------------------------------------- /version/build.gradle: -------------------------------------------------------------------------------- 1 | group 'me.clip' 2 | version '2.0' 3 | 4 | dependencies { 5 | compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") 6 | } -------------------------------------------------------------------------------- /version/src/main/kotlin/me/clip/voteparty/version/EffectType.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.version 2 | 3 | enum class EffectType 4 | { 5 | 6 | EXPLOSION_NORMAL, 7 | EXPLOSION_LARGE, 8 | EXPLOSION_HUGE, 9 | FIREWORKS_SPARK, 10 | WATER_BUBBLE, 11 | WATER_SPLASH, 12 | WATER_WAKE, 13 | SUSPENDED, 14 | SUSPENDED_DEPTH, 15 | CRIT, 16 | CRIT_MAGIC, 17 | SMOKE_NORMAL, 18 | SMOKE_LARGE, 19 | SPELL, 20 | SPELL_INSTANT, 21 | SPELL_MOB, 22 | SPELL_MOB_AMBIENT, 23 | SPELL_WITCH, 24 | DRIP_WATER, 25 | DRIP_LAVA, 26 | VILLAGER_ANGRY, 27 | VILLAGER_HAPPY, 28 | TOWN_AURA, 29 | NOTE, 30 | PORTAL, 31 | ENCHANTMENT_TABLE, 32 | FLAME, 33 | LAVA, 34 | CLOUD, 35 | REDSTONE, 36 | SNOWBALL, 37 | SNOW_SHOVEL, 38 | SLIME, 39 | HEART, 40 | BARRIER, 41 | ITEM_CRACK, 42 | BLOCK_CRACK, 43 | BLOCK_DUST, 44 | WATER_DROP, 45 | MOB_APPEARANCE, 46 | DRAGON_BREATH, 47 | END_ROD, 48 | DAMAGE_INDICATOR, 49 | SWEEP_ATTACK, 50 | FALLING_DUST, 51 | TOTEM, 52 | SPIT, 53 | SQUID_INK, 54 | BUBBLE_POP, 55 | CURRENT_DOWN, 56 | BUBBLE_COLUMN_UP, 57 | NAUTILUS, 58 | DOLPHIN, 59 | SNEEZE, 60 | CAMPFIRE_COSY_SMOKE, 61 | CAMPFIRE_SIGNAL_SMOKE, 62 | COMPOSTER, 63 | FLASH, 64 | FALLING_LAVA, 65 | LANDING_LAVA, 66 | FALLING_WATER; 67 | 68 | 69 | companion object 70 | { 71 | 72 | private val values = values() 73 | 74 | fun find(text: String): EffectType? 75 | { 76 | return values.find { it.name.equals(text, true) } 77 | } 78 | 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /version/src/main/kotlin/me/clip/voteparty/version/VersionHook.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.version 2 | 3 | import org.bukkit.Color 4 | import org.bukkit.Location 5 | 6 | interface VersionHook 7 | { 8 | 9 | fun display(type: EffectType, location: Location, offsetX: Double, offsetY: Double, offsetZ: Double, speed: Double, count: Int, color: Color? = null) 10 | 11 | } -------------------------------------------------------------------------------- /version_new/build.gradle: -------------------------------------------------------------------------------- 1 | group 'me.clip' 2 | version '2.0' 3 | 4 | dependencies { 5 | implementation project(":version") 6 | compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") 7 | } -------------------------------------------------------------------------------- /version_new/src/main/kotlin/me/clip/voteparty/version/VersionHookNew.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.version 2 | 3 | import com.cryptomorin.xseries.particles.XParticle 4 | import org.bukkit.Color 5 | import org.bukkit.Location 6 | import org.bukkit.Particle 7 | import org.bukkit.Particle.DustOptions 8 | 9 | class VersionHookNew : VersionHook 10 | { 11 | 12 | override fun display(type: EffectType, location: Location, offsetX: Double, offsetY: Double, offsetZ: Double, speed: Double, count: Int, color: Color?) 13 | { 14 | 15 | val world = location.world ?: return 16 | val optionalParticle = XParticle.of(type.name) 17 | 18 | if (!optionalParticle.isPresent) 19 | { 20 | return 21 | } 22 | 23 | val particle = optionalParticle.get() 24 | 25 | if (particle.get().dataType == DustOptions::class.java) 26 | { 27 | return world.spawnParticle(particle.get(), location, 1, if (color == null) OPTION else DustOptions(color, 0.8F)) 28 | } 29 | 30 | when (particle) 31 | { 32 | in SINGLE -> 33 | { 34 | world.spawnParticle(particle.get(), location, count) 35 | } 36 | in SPELLS -> 37 | { 38 | val r: Double 39 | val g: Double 40 | val b: Double 41 | 42 | if (color == null) 43 | { 44 | r = 0.0 45 | g = 0.0 46 | b = 0.0 47 | } 48 | else 49 | { 50 | r = color.red / 255.0 51 | g = color.green / 255.0 52 | b = color.blue / 255.0 53 | } 54 | 55 | world.spawnParticle(particle.get(), location, count, r, g, b, 1) 56 | } 57 | XParticle.NOTE -> 58 | { 59 | val note = if (color == null) 60 | { 61 | 0.0 62 | } 63 | else 64 | { 65 | color.red / 24.0 66 | } 67 | 68 | world.spawnParticle(particle.get(), location, count, note, offsetY, offsetZ, 1) 69 | } 70 | else -> 71 | { 72 | world.spawnParticle(particle.get(), location, count, offsetX, offsetY, offsetZ, 0.001) 73 | } 74 | } 75 | } 76 | 77 | private companion object 78 | { 79 | 80 | private val OPTION = DustOptions(Color.RED, 0.8F) 81 | 82 | private val SPELLS = setOf( 83 | XParticle.ENTITY_EFFECT, 84 | ) 85 | 86 | private val SINGLE = setOf( 87 | XParticle.BUBBLE, 88 | XParticle.FISHING, 89 | XParticle.CRIT, 90 | XParticle.ENCHANTED_HIT, 91 | XParticle.SMOKE, 92 | XParticle.LARGE_SMOKE, 93 | XParticle.PORTAL, 94 | XParticle.ENCHANT, 95 | XParticle.FLAME, 96 | XParticle.CLOUD, 97 | XParticle.DRAGON_BREATH, 98 | XParticle.END_ROD, 99 | XParticle.DAMAGE_INDICATOR, 100 | XParticle.TOTEM_OF_UNDYING, 101 | XParticle.SPIT, 102 | XParticle.SQUID_INK, 103 | XParticle.BUBBLE_POP, 104 | XParticle.BUBBLE_COLUMN_UP, 105 | XParticle.NAUTILUS 106 | ) 107 | 108 | } 109 | 110 | } -------------------------------------------------------------------------------- /version_old/build.gradle: -------------------------------------------------------------------------------- 1 | group 'me.clip' 2 | version '2.0' 3 | 4 | 5 | repositories { 6 | maven { 7 | url = "https://repo.glaremasters.me/repository/public/" 8 | } 9 | maven { 10 | url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation project(":version") 16 | implementation "org.inventivetalent:particleapi:+" 17 | 18 | compileOnly("org.spigotmc:spigot-api") { 19 | version { 20 | require("1.8.8-R0.1-SNAPSHOT") 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /version_old/src/main/kotlin/me/clip/voteparty/version/VersionHookOld.kt: -------------------------------------------------------------------------------- 1 | package me.clip.voteparty.version 2 | 3 | import org.bukkit.Color 4 | import org.bukkit.Location 5 | import org.inventivetalent.particle.ParticleEffect 6 | 7 | class VersionHookOld : VersionHook 8 | { 9 | 10 | override fun display(type: EffectType, location: Location, offsetX: Double, offsetY: Double, offsetZ: Double, speed: Double, count: Int, color: Color?) 11 | { 12 | val effect = resolve(type) ?: return 13 | 14 | if (color != null && effect.hasFeature(ParticleEffect.Feature.COLOR)) 15 | { 16 | effect.sendColor(location.world.players, location, color) 17 | } 18 | else 19 | { 20 | effect.send(location.world.players, location, offsetX, offsetY, offsetZ, speed, count) 21 | } 22 | } 23 | 24 | 25 | private companion object 26 | { 27 | private val VALUES = ParticleEffect.entries.toTypedArray() 28 | 29 | 30 | private fun resolve(type: EffectType): ParticleEffect? 31 | { 32 | return VALUES.find { it.name.equals(type.name, true) } 33 | } 34 | 35 | } 36 | 37 | } --------------------------------------------------------------------------------