Initial Commit
This commit is contained in:
119
.gitignore
vendored
Normal file
119
.gitignore
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
||||||
|
runs/
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
78
build.gradle
Normal file
78
build.gradle
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
|
id 'com.gradleup.shadow' version '9.0.0-beta10'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'me.trouper'
|
||||||
|
version = '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
maven {
|
||||||
|
name = "papermc-repo"
|
||||||
|
url = "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "sonatype"
|
||||||
|
url = "https://oss.sonatype.org/content/groups/public/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = uri("https://repo.codemc.io/repository/maven-releases/")
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = uri("https://repo.codemc.io/repository/maven-snapshots/")
|
||||||
|
}
|
||||||
|
maven{
|
||||||
|
url = uri("https://jitpack.io")
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "CodeMC"
|
||||||
|
url = uri("https://repo.codemc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
|
||||||
|
compileOnly("com.github.retrooper:packetevents-spigot:2.8.0")
|
||||||
|
compileOnly("com.gitlab.ruany:LiteBansAPI:0.6.1")
|
||||||
|
compileOnly("de.tr7zw:item-nbt-api-plugin:2.15.0")
|
||||||
|
implementation("me.trouper:alias:1.0-1.21.1-SNAPSHOT")
|
||||||
|
implementation("club.minnced:discord-webhooks:0.8.4")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
minecraftVersion("1.21.5")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def targetJavaVersion = 21
|
||||||
|
java {
|
||||||
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
|
if (JavaVersion.current() < javaVersion) {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
|
||||||
|
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||||
|
options.release.set(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
def props = [version: version]
|
||||||
|
inputs.properties props
|
||||||
|
filteringCharset 'UTF-8'
|
||||||
|
filesMatching('plugin.yml') {
|
||||||
|
expand props
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
minimize()
|
||||||
|
}
|
||||||
0
gradle.properties
Normal file
0
gradle.properties
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
249
gradlew
vendored
Executable file
249
gradlew
vendored
Executable file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
gradlew.bat
vendored
Normal file
92
gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
1
settings.gradle
Normal file
1
settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'CloneDupeCore'
|
||||||
59
src/main/java/me/trouper/clonedupecore/CloneDupeCore.java
Normal file
59
src/main/java/me/trouper/clonedupecore/CloneDupeCore.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package me.trouper.clonedupecore;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||||
|
import me.trouper.clonedupecore.server.Manager;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public final class CloneDupeCore extends JavaPlugin {
|
||||||
|
|
||||||
|
private static CloneDupeCore instance;
|
||||||
|
private Manager manager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
getLogger().info("Setting PacketEvents API");
|
||||||
|
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
|
||||||
|
PacketEvents.getAPI().load();
|
||||||
|
|
||||||
|
getLogger().info("Instantiating Plugin");
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
getLogger().info("Initializing PacketEvents");
|
||||||
|
PacketEvents.getAPI().init();
|
||||||
|
|
||||||
|
getLogger().info("Instantiating Manager");
|
||||||
|
manager = new Manager(instance);
|
||||||
|
|
||||||
|
getLogger().info("Initializing Manager");
|
||||||
|
manager.init();
|
||||||
|
|
||||||
|
getLogger().info("Successfully enabled CloneDupeCore.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
getLogger().info("Cleaning up...");
|
||||||
|
manager.cleanup();
|
||||||
|
getLogger().info("Saved all IO files.");
|
||||||
|
manager.io.saveAll();
|
||||||
|
|
||||||
|
PacketEvents.getAPI().terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CloneDupeCore getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getNameSpace() {
|
||||||
|
return new NamespacedKey(getInstance(),"clone_dupe_core");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Manager getManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/java/me/trouper/clonedupecore/data/Data.java
Normal file
24
src/main/java/me/trouper/clonedupecore/data/Data.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package me.trouper.clonedupecore.data;
|
||||||
|
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.data.io.Config;
|
||||||
|
import me.trouper.clonedupecore.data.io.NBTConfig;
|
||||||
|
import me.trouper.clonedupecore.data.io.Storage;
|
||||||
|
|
||||||
|
public interface Data {
|
||||||
|
default Config getConfig() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
default Storage getStorage() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
default NBTConfig getNBT() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.nbtConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
default IO getIO() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/me/trouper/clonedupecore/data/IO.java
Executable file
48
src/main/java/me/trouper/clonedupecore/data/IO.java
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
package me.trouper.clonedupecore.data;
|
||||||
|
|
||||||
|
import me.trouper.alias.data.JsonSerializable;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.data.io.Config;
|
||||||
|
import me.trouper.clonedupecore.data.io.NBTConfig;
|
||||||
|
import me.trouper.clonedupecore.data.io.Storage;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class IO {
|
||||||
|
public final File DATA_FOLDER;
|
||||||
|
public final File CONFIG_FILE;
|
||||||
|
public final File STORAGE_FILE;
|
||||||
|
public final File NBT_FILE;
|
||||||
|
|
||||||
|
public Config config;
|
||||||
|
public Storage storage;
|
||||||
|
public NBTConfig nbtConfig;
|
||||||
|
|
||||||
|
public IO(File dataFolder) {
|
||||||
|
DATA_FOLDER = dataFolder;
|
||||||
|
CONFIG_FILE = new File(DATA_FOLDER,"/config.json");
|
||||||
|
STORAGE_FILE = new File(DATA_FOLDER, "/storage.json");
|
||||||
|
NBT_FILE = new File(DATA_FOLDER, "/enchants.json");
|
||||||
|
config = new Config();
|
||||||
|
storage = new Storage();
|
||||||
|
nbtConfig = new NBTConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadAll() {
|
||||||
|
CloneDupeCore.getInstance().getLogger().info("Loading all IO Files");
|
||||||
|
config = JsonSerializable.load(CONFIG_FILE,Config.class,new Config());
|
||||||
|
storage = JsonSerializable.load(STORAGE_FILE,Storage.class,new Storage());
|
||||||
|
nbtConfig = JsonSerializable.load(NBT_FILE, NBTConfig.class,new NBTConfig());
|
||||||
|
saveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAll() {
|
||||||
|
CloneDupeCore.getInstance().getLogger().info("Saving all IO Files");
|
||||||
|
if (config == null) config = new Config();
|
||||||
|
if (storage == null) storage = new Storage();
|
||||||
|
if (nbtConfig == null) nbtConfig = new NBTConfig();
|
||||||
|
config.save();
|
||||||
|
storage.save();
|
||||||
|
nbtConfig.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/main/java/me/trouper/clonedupecore/data/io/Config.java
Executable file
56
src/main/java/me/trouper/clonedupecore/data/io/Config.java
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
package me.trouper.clonedupecore.data.io;
|
||||||
|
|
||||||
|
import me.trouper.alias.data.JsonSerializable;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Config implements JsonSerializable<Config> {
|
||||||
|
|
||||||
|
public boolean debugMode = false;
|
||||||
|
public List<String> debuggerExclusions = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getFile() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.CONFIG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
CloneDupeCore.getInstance().getLogger().info("Saving Config...");
|
||||||
|
JsonSerializable.super.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Messages messages = new Messages();
|
||||||
|
|
||||||
|
public class Messages {
|
||||||
|
public int mainColor = 0xFF88AA;
|
||||||
|
public int secondaryColor = 0xFFDDDD;
|
||||||
|
public String flatPrefix = "§c§lCloneDupe §8» §7";
|
||||||
|
public String pluginName = "CloneDupe";
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> nbtWhitelist = new ArrayList<>(List.of(
|
||||||
|
"8447c822-6175-4081-b5aa-13fc6c6e69d2",
|
||||||
|
"9ccc7b49-7695-40f8-9990-f7436645e4ca",
|
||||||
|
"049460f7-21cb-42f5-8059-d42752bf406f",
|
||||||
|
"299a9071-ec6d-4d2c-8c7b-d7bba934fbe5"
|
||||||
|
));
|
||||||
|
|
||||||
|
public String banWebhook = "https://discord.com/api/webhooks/1386722424585719809/d8hFffcvqlPEpPSSnOPzGJ3TKgcM4nPJnTsE976-yRsHYgqB9IgyUf2nBJKIepxV_sr6";
|
||||||
|
|
||||||
|
public List<String> banTemplates = new ArrayList<>(List.of(
|
||||||
|
"hacking",
|
||||||
|
"bugs",
|
||||||
|
"dupes",
|
||||||
|
"evasion",
|
||||||
|
"screen"
|
||||||
|
));
|
||||||
|
|
||||||
|
public List<String> getBanTemplateNames() {
|
||||||
|
return new ArrayList<>(banTemplates);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package me.trouper.clonedupecore.data.io;
|
||||||
|
|
||||||
|
import me.trouper.alias.data.JsonSerializable;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NBTConfig implements JsonSerializable<NBTConfig> {
|
||||||
|
@Override
|
||||||
|
public File getFile() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.NBT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
CloneDupeCore.getInstance().getLogger().info("Saving Storage...");
|
||||||
|
JsonSerializable.super.save();
|
||||||
|
}
|
||||||
|
public RateLimit rateLimit = new RateLimit();
|
||||||
|
|
||||||
|
public class RateLimit {
|
||||||
|
public int maxOverhead = 32768;
|
||||||
|
public int rateLimitBytes = 16348;
|
||||||
|
public int byteDecay = 1024; // Every Minute
|
||||||
|
public int rateLimitItems = 10;
|
||||||
|
public int itemDecay = 5; // Every 10 seconds
|
||||||
|
public List<String> punishmentCommands = List.of("kick %player% Internal Exception: io.netty.handler.codec.DecoderException: java.lang.RuntimeException: Tried to read NBT tag that was too big; tried to allocate %s bytes where max allowed: %s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowName = true;
|
||||||
|
public boolean allowLore = true;
|
||||||
|
public boolean allowAttributes = false;
|
||||||
|
public boolean allowPotions = false;
|
||||||
|
public boolean allowCustomConsumables = false;
|
||||||
|
public boolean allowCustomTools = false;
|
||||||
|
public boolean allowBooks = false;
|
||||||
|
public boolean allowRecursion = true;
|
||||||
|
public int maxCustomData = 64;
|
||||||
|
|
||||||
|
public int globalMaxEnchant = 5;
|
||||||
|
public int maxMending = 1;
|
||||||
|
public int maxUnbreaking = 3;
|
||||||
|
public int maxCurseOfVanishing = 1;
|
||||||
|
public int maxAquaAffinity = 1;
|
||||||
|
public int maxBlastProtection = 4;
|
||||||
|
public int maxCurseOfBinding = 1;
|
||||||
|
public int maxDepthStrider = 3;
|
||||||
|
public int maxFeatherFalling = 4;
|
||||||
|
public int maxFireProtection = 4;
|
||||||
|
public int maxFrostWalker = 2;
|
||||||
|
public int maxProjectileProtection = 4;
|
||||||
|
public int maxProtection = 4;
|
||||||
|
public int maxRespiration = 3;
|
||||||
|
public int maxSoulSpeed = 3;
|
||||||
|
public int maxThorns = 3;
|
||||||
|
public int maxSwiftSneak = 3;
|
||||||
|
public int maxBaneOfArthropods = 5;
|
||||||
|
public int maxEfficiency = 5;
|
||||||
|
public int maxFireAspect = 2;
|
||||||
|
public int maxLooting = 3;
|
||||||
|
public int maxImpaling = 5;
|
||||||
|
public int maxKnockback = 2;
|
||||||
|
public int maxSharpness = 5;
|
||||||
|
public int maxSmite = 5;
|
||||||
|
public int maxSweepingEdge = 3;
|
||||||
|
public int maxChanneling = 1;
|
||||||
|
public int maxFlame = 1;
|
||||||
|
public int maxInfinity = 1;
|
||||||
|
public int maxLoyalty = 3;
|
||||||
|
public int maxRiptide = 3;
|
||||||
|
public int maxMultishot = 1;
|
||||||
|
public int maxPiercing = 4;
|
||||||
|
public int maxPower = 5;
|
||||||
|
public int maxPunch = 2;
|
||||||
|
public int maxQuickCharge = 3;
|
||||||
|
public int maxFortune = 3;
|
||||||
|
public int maxLuckOfTheSea = 3;
|
||||||
|
public int maxLure = 3;
|
||||||
|
public int maxSilkTouch = 1;
|
||||||
|
public int maxBreach = 4;
|
||||||
|
public int maxDensity = 5;
|
||||||
|
public int maxWindBurst = 3;
|
||||||
|
|
||||||
|
}
|
||||||
26
src/main/java/me/trouper/clonedupecore/data/io/Storage.java
Normal file
26
src/main/java/me/trouper/clonedupecore/data/io/Storage.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package me.trouper.clonedupecore.data.io;
|
||||||
|
|
||||||
|
import me.trouper.alias.data.JsonSerializable;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class Storage implements JsonSerializable<Storage> {
|
||||||
|
@Override
|
||||||
|
public File getFile() {
|
||||||
|
return CloneDupeCore.getInstance().getManager().io.STORAGE_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
CloneDupeCore.getInstance().getLogger().info("Saving Storage...");
|
||||||
|
JsonSerializable.super.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> disabledOwnParticles = new HashSet<>();
|
||||||
|
public Set<String> disabledGlobalParticles = new HashSet<>();
|
||||||
|
}
|
||||||
58
src/main/java/me/trouper/clonedupecore/server/Manager.java
Normal file
58
src/main/java/me/trouper/clonedupecore/server/Manager.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package me.trouper.clonedupecore.server;
|
||||||
|
|
||||||
|
import me.trouper.alias.Alias;
|
||||||
|
import me.trouper.alias.data.Common;
|
||||||
|
import me.trouper.alias.server.systems.tracing.BlockDisplayRaytracer;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.data.IO;
|
||||||
|
import me.trouper.clonedupecore.server.trims.TrimManager;
|
||||||
|
import me.trouper.clonedupecore.server.trims.animations.*;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public class Manager {
|
||||||
|
|
||||||
|
public IO io;
|
||||||
|
public Common common;
|
||||||
|
public TrimManager trimManager;
|
||||||
|
|
||||||
|
public Manager(JavaPlugin instance) {
|
||||||
|
io = new IO(instance.getDataFolder());
|
||||||
|
common = new Common(instance.getClass().getPackageName(),0xFF00AA,0xFFDDDD,"CloneDupeCore","CloneDupe> ",false);
|
||||||
|
trimManager = new TrimManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
io.loadAll();
|
||||||
|
|
||||||
|
setCommon();
|
||||||
|
|
||||||
|
Alias.register(CloneDupeCore.getInstance(),common);
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
trimManager.register(new AmethystAnimation());
|
||||||
|
trimManager.register(new AmethystAnimation());
|
||||||
|
trimManager.register(new CopperAnimation());
|
||||||
|
trimManager.register(new DiamondAnimation());
|
||||||
|
trimManager.register(new EmeraldAnimation());
|
||||||
|
trimManager.register(new GoldAnimation());
|
||||||
|
trimManager.register(new IronAnimation());
|
||||||
|
trimManager.register(new LapisAnimation());
|
||||||
|
trimManager.register(new NetheriteAnimation());
|
||||||
|
trimManager.register(new QuartzAnimation());
|
||||||
|
trimManager.register(new RedstoneAnimation());
|
||||||
|
trimManager.startTicking();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommon() {
|
||||||
|
common.setMainColor(io.config.messages.mainColor);
|
||||||
|
common.setSecondaryColor(io.config.messages.secondaryColor);
|
||||||
|
common.setFlatPrefix(io.config.messages.flatPrefix);
|
||||||
|
common.setPluginName(io.config.messages.pluginName);
|
||||||
|
common.setDebugMode(io.config.debugMode);
|
||||||
|
io.config.debuggerExclusions.forEach(exclusion -> common.addDebuggerExclusion(exclusion));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
BlockDisplayRaytracer.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
package me.trouper.clonedupecore.server.commands;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.commands.Args;
|
||||||
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
|
import me.trouper.alias.server.commands.Permission;
|
||||||
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.utils.FormatUtils;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidArmorType;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
||||||
|
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||||
|
import org.bukkit.inventory.meta.trim.TrimPattern;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@CommandRegistry(value = "clonedupecore",permission = @Permission("clonedupe.admin"))
|
||||||
|
public class AdminCommand implements QuickCommand, Data {
|
||||||
|
@Override
|
||||||
|
public void handleCommand(CommandSender commandSender, Command command, String s, Args args) {
|
||||||
|
if (args.getSize() < 1) {
|
||||||
|
errorAny(commandSender,"You must choose an argument.");
|
||||||
|
}
|
||||||
|
switch (args.get(0).toString()) {
|
||||||
|
case "debug" -> handleDebug(commandSender,args);
|
||||||
|
case "trim" -> handleTrim(commandSender,args);
|
||||||
|
case "reload" -> handleReload(commandSender,args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCompletion(CommandSender commandSender, Command command, String s, Args args, CompletionBuilder b) {
|
||||||
|
b.then(
|
||||||
|
b.arg("debug")
|
||||||
|
.then(
|
||||||
|
b.arg("toggle")
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
b.arg("exclude")
|
||||||
|
.then(
|
||||||
|
b.arg("Class.method")))
|
||||||
|
.then(
|
||||||
|
b.arg("include")
|
||||||
|
.then(
|
||||||
|
b.arg(getConfig().debuggerExclusions)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).then(
|
||||||
|
b.arg("trim")
|
||||||
|
.then(
|
||||||
|
b.argEnum(ValidMaterial.class)
|
||||||
|
.then(
|
||||||
|
b.argEnum(ValidArmorType.class)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReload(CommandSender sender, Args args) {
|
||||||
|
successAny(sender,"Reloading IO and common...");
|
||||||
|
getIO().loadAll();
|
||||||
|
CloneDupeCore.getInstance().getManager().setCommon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleTrim(CommandSender sender, Args args) {
|
||||||
|
if (args.getSize() < 2) {
|
||||||
|
errorAny(sender, "Usage: /clonedupecore trim [material] [armortype]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(sender instanceof Player p)) {
|
||||||
|
errorAny(sender,"Only players can use this sub-command.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidMaterial validMaterial = main.randomizer().getRandomElement(ValidMaterial.values());
|
||||||
|
ValidArmorType validArmorType = main.randomizer().getRandomElement(ValidArmorType.values());
|
||||||
|
if (args.getSize() >= 2) validMaterial = args.get(1).toEnum(ValidMaterial.class);
|
||||||
|
if (args.getSize() >= 3) validArmorType = args.get(2).toEnum(ValidArmorType.class);
|
||||||
|
|
||||||
|
TrimPattern pattern = TrimPattern.SILENCE;
|
||||||
|
TrimMaterial material = validMaterial.getCanonical();
|
||||||
|
|
||||||
|
if (material == null) material = main.randomizer().getRandomElement(ValidMaterial.values()).getCanonical();
|
||||||
|
|
||||||
|
p.getEquipment().setHelmet(createTestArmor(new ItemStack(validArmorType.getHelmet()),pattern,material));
|
||||||
|
p.getEquipment().setChestplate(createTestArmor(new ItemStack(validArmorType.getChestplate()),pattern,material));
|
||||||
|
p.getEquipment().setLeggings(createTestArmor(new ItemStack(validArmorType.getLeggings()),pattern,material));
|
||||||
|
p.getEquipment().setBoots(createTestArmor(new ItemStack(validArmorType.getBoots()),pattern,material));
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
double finalI = i;
|
||||||
|
Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{
|
||||||
|
DisplayUtils.ring(p.getLocation().clone().add(0, finalI / 5D,0),0.5, Color.RED,0.5F);
|
||||||
|
},i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
double finalI = i;
|
||||||
|
Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{
|
||||||
|
DisplayUtils.ring(p.getLocation().clone().add(0,2,0).subtract(0,finalI / 5D,0),0.5,Color.RED,0.5F);
|
||||||
|
},10 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
new SoundPlayer(Sound.BLOCK_BEACON_ACTIVATE).playTo(p);
|
||||||
|
|
||||||
|
infoAny(sender,"You now are wearing {0} with {1} {2} trim.", "Netherite",FormatUtils.formatEnum(validMaterial),"Silence");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack createTestArmor(ItemStack piece, TrimPattern trimPattern, TrimMaterial trimMaterial) {
|
||||||
|
ItemMeta meta = piece.getItemMeta();
|
||||||
|
if (!(meta instanceof ArmorMeta armor)) {
|
||||||
|
throw new IllegalArgumentException("You must input armor ONLY");
|
||||||
|
}
|
||||||
|
|
||||||
|
armor.displayName(Text.color("&eTesting Armor").decoration(TextDecoration.ITALIC,false));
|
||||||
|
armor.lore(List.of(
|
||||||
|
Text.color("&8&l| &7%s".formatted(FormatUtils.formatEnum(ValidMaterial.validate(trimMaterial)))).decoration(TextDecoration.ITALIC,false),
|
||||||
|
Text.color("&8&l| &7Won't Break").decoration(TextDecoration.ITALIC,false),
|
||||||
|
Text.color("&8&l| &7Vanishes on death").decoration(TextDecoration.ITALIC,false),
|
||||||
|
Text.color("&8&l| &7This armor is for testing purposes &c&lONLY&7!").decoration(TextDecoration.ITALIC,false)
|
||||||
|
));
|
||||||
|
armor.addEnchant(Enchantment.VANISHING_CURSE,1,true);
|
||||||
|
armor.addEnchant(Enchantment.PROTECTION, 4, true);
|
||||||
|
armor.setUnbreakable(true);
|
||||||
|
armor.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
armor.addItemFlags(ItemFlag.HIDE_UNBREAKABLE);
|
||||||
|
armor.addItemFlags(ItemFlag.HIDE_ARMOR_TRIM);
|
||||||
|
|
||||||
|
armor.setTrim(new ArmorTrim(trimMaterial,trimPattern));
|
||||||
|
|
||||||
|
piece.setItemMeta(armor);
|
||||||
|
return piece;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDebug(CommandSender sender, Args args) {
|
||||||
|
if (args.getSize() < 2) {
|
||||||
|
errorAny(sender, "Usage: /clonedupecore debug <toggle|include|exclude>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String sub = args.get(1).toString();
|
||||||
|
|
||||||
|
switch (sub) {
|
||||||
|
case "toggle" -> {
|
||||||
|
boolean result = false;
|
||||||
|
getConfig().debugMode = result = !getConfig().debugMode;
|
||||||
|
getConfig().save();
|
||||||
|
|
||||||
|
CloneDupeCore.getInstance().getManager().common.setDebugMode(result);
|
||||||
|
|
||||||
|
successAny(sender,"Toggled debug mode {0}.",result ? "on" : "off");
|
||||||
|
}
|
||||||
|
case "exclude" -> {
|
||||||
|
if (args.getSize() < 3) {
|
||||||
|
errorAny(sender, "Usage: /clonedupecore debug exclude <method>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String exclusion = args.get(2).toString();
|
||||||
|
getConfig().debuggerExclusions.add(exclusion);
|
||||||
|
getConfig().save();
|
||||||
|
|
||||||
|
CloneDupeCore.getInstance().getManager().common.addDebuggerExclusion(exclusion);
|
||||||
|
|
||||||
|
successAny(sender, "Excluded {0} from the debugger.", exclusion);
|
||||||
|
}
|
||||||
|
case "include" -> {
|
||||||
|
if (args.getSize() < 3) {
|
||||||
|
errorAny(sender, "Usage: /clonedupecore debug include <method>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String exclusion = args.get(2).toString();
|
||||||
|
getConfig().debuggerExclusions.remove(exclusion);
|
||||||
|
getConfig().save();
|
||||||
|
|
||||||
|
CloneDupeCore.getInstance().getManager().common.removeDebuggerExclusion(exclusion);
|
||||||
|
|
||||||
|
successAny(sender, "Removed exclusion for {0} on the debugger.", exclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package me.trouper.clonedupecore.server.commands;
|
||||||
|
|
||||||
|
import club.minnced.discord.webhook.WebhookClient;
|
||||||
|
import club.minnced.discord.webhook.WebhookClientBuilder;
|
||||||
|
import club.minnced.discord.webhook.send.WebhookEmbed;
|
||||||
|
import club.minnced.discord.webhook.send.WebhookEmbedBuilder;
|
||||||
|
import me.trouper.alias.server.commands.Args;
|
||||||
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
|
import me.trouper.alias.server.commands.Permission;
|
||||||
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.utils.misc.TimeUtils;
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.LiteBansManager;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.WrappedEntry;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.animations.*;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@CommandRegistry(
|
||||||
|
value = "offend",
|
||||||
|
usage = "/offend <player> <query|punish> [template]",
|
||||||
|
permission = @Permission("clonedupe.offend"),
|
||||||
|
printStackTrace = true
|
||||||
|
)
|
||||||
|
public class OffendCommand implements QuickCommand, Data {
|
||||||
|
|
||||||
|
private final LiteBansManager liteBansManager = new LiteBansManager();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(CommandSender sender, Command command, String label, Args args) {
|
||||||
|
if (args.getSize() < 2) {
|
||||||
|
errorAny(sender, "Incomplete command. Correct usage: ", getRegistry().usage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflinePlayer target = Bukkit.getOfflinePlayer(args.get(0).toString());
|
||||||
|
|
||||||
|
if (target == null || !target.hasPlayedBefore()) {
|
||||||
|
errorAny(sender, "That player has never joined before.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sub = args.get(1).toString();
|
||||||
|
String template = args.getSize() >= 3 ? args.get(2).toString() : null;
|
||||||
|
|
||||||
|
if ("query".equals(sub)) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(main.getPlugin(), ()->{
|
||||||
|
handleQuery(sender, target, template);
|
||||||
|
});
|
||||||
|
} else if ("punish".equals(sub)) {
|
||||||
|
if (template == null) {
|
||||||
|
errorAny(sender, "You must specify a ban template!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!getConfig().banTemplates.contains(template)) {
|
||||||
|
errorAny(sender, "That template is invalid! Available templates: " +
|
||||||
|
String.join(", ", getConfig().banTemplates));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(main.getPlugin(), ()->{
|
||||||
|
handlePunish(sender, target, template);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCompletion(CommandSender commandSender, Command command, String label, Args args, CompletionBuilder b) {
|
||||||
|
b.then(
|
||||||
|
b.argOnlinePlayers()
|
||||||
|
.then(
|
||||||
|
b.arg("query", "punish")
|
||||||
|
.then(
|
||||||
|
b.arg(getConfig().getBanTemplateNames())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleQuery(CommandSender sender, OfflinePlayer target, String template) {
|
||||||
|
if (template == null) {
|
||||||
|
List<WrappedEntry> allBans = liteBansManager.getPlayerBans(target);
|
||||||
|
|
||||||
|
Component historyMessage = Text.format(Text.Pallet.INFO, "All bans for {0}: ", target.getName())
|
||||||
|
.appendNewline();
|
||||||
|
|
||||||
|
if (allBans.isEmpty()) {
|
||||||
|
historyMessage = historyMessage.append(Text.format(Text.Pallet.LOCATION, "No bans found."));
|
||||||
|
} else {
|
||||||
|
for (WrappedEntry ban : allBans) {
|
||||||
|
String status = ban.isActive() ? "Active" : "Expired/Unbanned";
|
||||||
|
String duration = ban.isPermanent() ? "Permanent" : TimeUtils.formatTime(ban.getDateEnd());
|
||||||
|
|
||||||
|
historyMessage = historyMessage
|
||||||
|
.append(Text.format(Text.Pallet.LOCATION,
|
||||||
|
"{0} - {1} - {2} - {3}",
|
||||||
|
TimeUtils.formatTime(ban.getDateStart()),
|
||||||
|
ban.getReason(),
|
||||||
|
duration,
|
||||||
|
status))
|
||||||
|
.appendNewline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(historyMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
short index = (short) getConfig().banTemplates.indexOf(template);
|
||||||
|
List<WrappedEntry> templateBans = liteBansManager.getPlayerBansByTemplate(target, index);
|
||||||
|
|
||||||
|
Component historyMessage = Text.format(Text.Pallet.INFO,
|
||||||
|
"{0} template bans for {1}: ", template, target.getName()).appendNewline();
|
||||||
|
|
||||||
|
if (templateBans.isEmpty()) {
|
||||||
|
historyMessage = historyMessage.append(Text.format(Text.Pallet.LOCATION, "No bans found for this template."));
|
||||||
|
} else {
|
||||||
|
for (WrappedEntry ban : templateBans) {
|
||||||
|
String status = ban.isActive() ? "Active" : "Expired/Unbanned";
|
||||||
|
String duration = ban.isPermanent() ? "Permanent" : TimeUtils.formatTime(ban.getDateEnd());
|
||||||
|
|
||||||
|
historyMessage = historyMessage
|
||||||
|
.append(Text.format(Text.Pallet.LOCATION,
|
||||||
|
"{0} - {1} - {2}",
|
||||||
|
TimeUtils.formatTime(ban.getDateStart()),
|
||||||
|
duration,
|
||||||
|
status))
|
||||||
|
.appendNewline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(historyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePunish(CommandSender sender, OfflinePlayer target, String template) {
|
||||||
|
if (liteBansManager.isPlayerBanned(target)) {
|
||||||
|
WrappedEntry activeBan = liteBansManager.getActiveBan(target);
|
||||||
|
if (activeBan != null) {
|
||||||
|
sender.sendMessage(Text.format(Text.Pallet.ERROR,
|
||||||
|
"{0} is already banned for: {1}", target.getName(), activeBan.getReason()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short index = (short) getConfig().banTemplates.indexOf(template);
|
||||||
|
int currentBans = liteBansManager.getBanCountByTemplate(target, index);
|
||||||
|
|
||||||
|
sender.sendMessage(Text.format(Text.Pallet.INFO,
|
||||||
|
"Executing ban for {0} using template {1} (Previous offenses: {2})",
|
||||||
|
target.getName(), template, currentBans));
|
||||||
|
|
||||||
|
Runnable banPlayer = () -> {
|
||||||
|
Verbose.send("Executing ban due to animation finishing.");
|
||||||
|
liteBansManager.executeBan(target, template, sender);
|
||||||
|
|
||||||
|
WebhookClientBuilder builder = new WebhookClientBuilder(getConfig().banWebhook);
|
||||||
|
WebhookEmbedBuilder embedBuilder = new WebhookEmbedBuilder();
|
||||||
|
embedBuilder.setAuthor(new WebhookEmbed.EmbedAuthor("New Ban","https://www.pngmart.com/files/23/Ban-Hammer-PNG-File-200x200.png","https://clonedupe.fun"));
|
||||||
|
embedBuilder.setTitle(new WebhookEmbed.EmbedTitle("Template: %s".formatted(template), null));
|
||||||
|
embedBuilder.addField(new WebhookEmbed.EmbedField(true,"Moderator",sender.getName()));
|
||||||
|
embedBuilder.addField(new WebhookEmbed.EmbedField(true,"Offender",target.getName() + " "));
|
||||||
|
try (WebhookClient c = builder.build()) {
|
||||||
|
c.send(embedBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(Text.format(Text.Pallet.SUCCESS, "Successfully banned {0} using template {1}", target.getName(), template));
|
||||||
|
};
|
||||||
|
|
||||||
|
Verbose.send("Banning with animation...");
|
||||||
|
PunishmentAnimation animation = main.randomizer().getRandomElement(ANIMATION_FACTORIES).create(main.getPlugin(), target.getPlayer(), banPlayer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
animation.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Verbose.send("Animation generated an exception before it could run! Banning player...");
|
||||||
|
e.printStackTrace();
|
||||||
|
banPlayer.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<PunishmentAnimation.AnimationFactory> ANIMATION_FACTORIES = Arrays.asList(
|
||||||
|
MatrixAnimation::new,
|
||||||
|
AnvilAnimation::new,
|
||||||
|
GwenAnimation::new,
|
||||||
|
LaserAnimation::new,
|
||||||
|
LightningAnimation::new
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package me.trouper.clonedupecore.server.commands;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.commands.Args;
|
||||||
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
|
import me.trouper.alias.server.commands.Permission;
|
||||||
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
@CommandRegistry(value = "ping", permission = @Permission("clonedupe.ping"),printStackTrace = true)
|
||||||
|
public class PingCommand implements QuickCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(CommandSender sender, Command command, String label, Args args) {
|
||||||
|
if (args.isEmpty() && sender instanceof Player target) {
|
||||||
|
displayPing(sender,target);
|
||||||
|
return;
|
||||||
|
} else if (sender instanceof ConsoleCommandSender) {
|
||||||
|
success(sender,Component.text("The console will always have {0} ping."),Component.text(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String argument = args.get(0).toString();
|
||||||
|
Player target = Bukkit.getPlayer(argument);
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
error(sender,Component.text("Could not find {0} online."),Component.text(argument));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPing(sender,target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCompletion(CommandSender commandSender, Command command, String s, Args args, CompletionBuilder b) {
|
||||||
|
b.then(
|
||||||
|
b.argOnlinePlayers()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayPing(CommandSender sender, Player target) {
|
||||||
|
final int ping = target.getPing();
|
||||||
|
if (sender instanceof Player player && player.equals(target)) {
|
||||||
|
target.sendActionBar(
|
||||||
|
Component.text("Your ping is", TextColor.color(0xFFAAAA))
|
||||||
|
.append(Component.text(": ", NamedTextColor.WHITE))
|
||||||
|
.append(Component.text(ping,NamedTextColor.AQUA))
|
||||||
|
.append(Component.text("ms",TextColor.color(0xFFDDDD)))
|
||||||
|
);
|
||||||
|
success(sender,Component.text("You have {0}ms of latency to the server."),Component.text(ping));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sender instanceof Player player) {
|
||||||
|
player.sendActionBar(
|
||||||
|
Component.text("Server <-> %s ping".formatted(target.getName()), TextColor.color(0xFFAAAA))
|
||||||
|
.append(Component.text(": ", NamedTextColor.WHITE))
|
||||||
|
.append(Component.text(ping,NamedTextColor.AQUA))
|
||||||
|
.append(Component.text("ms",TextColor.color(0xFFDDDD)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
success(sender,Component.text("{0} has {1}ms of latency to the server."),target.name(),Component.text(ping));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package me.trouper.clonedupecore.server.commands;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.commands.Args;
|
||||||
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
@CommandRegistry(
|
||||||
|
value = "trimeffect", usage = "/trimeffect <global|self>",
|
||||||
|
consoleAllowed = false,
|
||||||
|
blocksAllowed = false
|
||||||
|
)
|
||||||
|
public class TrimEffectCommand implements QuickCommand, Data {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(CommandSender commandSender, Command command, String s, Args args) {
|
||||||
|
Player p = (Player) commandSender;
|
||||||
|
if (args.getSize() != 1) {
|
||||||
|
errorAny(commandSender,"Correct Usage: ", getRegistry().usage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ("global".equals(args.get(0).toString())) {
|
||||||
|
if (getStorage().disabledGlobalParticles.add(p.getUniqueId().toString())) {
|
||||||
|
successAny(commandSender,"Disabled global Trim effects.");
|
||||||
|
} else {
|
||||||
|
getStorage().disabledGlobalParticles.remove(p.getUniqueId().toString());
|
||||||
|
successAny(commandSender,"Enabled global Trim effects.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (getStorage().disabledOwnParticles.add(p.getUniqueId().toString())) {
|
||||||
|
successAny(commandSender,"Disabled your own Trim effects.");
|
||||||
|
} else {
|
||||||
|
getStorage().disabledOwnParticles.remove(p.getUniqueId().toString());
|
||||||
|
successAny(commandSender,"Enabled your own Trim effects.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCompletion(CommandSender commandSender, Command command, String s, Args args, CompletionBuilder b) {
|
||||||
|
b.then(b.arg("global","self"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package me.trouper.clonedupecore.server.commands;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.commands.Args;
|
||||||
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
|
import me.trouper.alias.server.commands.Permission;
|
||||||
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
|
import me.trouper.alias.server.systems.AbstractWand;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.clonedupecore.server.trolls.*;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@CommandRegistry(value = "clonetroll",permission = @Permission("clonedupe.troll"),printStackTrace = true)
|
||||||
|
public class TrollCommand implements QuickCommand {
|
||||||
|
|
||||||
|
public final List<TrollFeature> trollRegistry = new ArrayList<>();
|
||||||
|
|
||||||
|
public TrollCommand() {
|
||||||
|
trollRegistry.addAll(List.of(
|
||||||
|
new DragTrollWand(),
|
||||||
|
new FlickerTroll(),
|
||||||
|
new LiarTroll(),
|
||||||
|
new LSDTroll(),
|
||||||
|
new MatrixTroll(),
|
||||||
|
new VoidTrollWand(),
|
||||||
|
new OrbitalTrollWand(),
|
||||||
|
new CameraTroll(),
|
||||||
|
new TestTrollWand()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(CommandSender sender, Command command, String label, Args args) {
|
||||||
|
Component helpMessage = Component.empty()
|
||||||
|
.append(Component.text("CloneDupe Troll Guide", NamedTextColor.RED).decorate(TextDecoration.BOLD)).appendNewline()
|
||||||
|
.append(Component.text("""
|
||||||
|
- These features can be used to mess with players -
|
||||||
|
SAFE trolls are purely packet based, and relogging will clear all their effects.
|
||||||
|
HARMLESS trolls are safe but not packet based. Relogging or rebooting may not clear all effects.
|
||||||
|
DAMAGING trolls may deal damage to the player's health and armor.
|
||||||
|
DESTRUCTIVE trolls may break blocks in the world, delete player items, or crash games. Some may be irreversible, so handle them carefully.
|
||||||
|
Use the *stop* argument to end or cancel a troll.
|
||||||
|
""",NamedTextColor.GRAY)).appendNewline()
|
||||||
|
.append(Component.text("Syntax",NamedTextColor.GOLD)
|
||||||
|
.append(Component.text(": ",NamedTextColor.WHITE)
|
||||||
|
.append(Component.text("/clonetroll <feature> [player] [stop]",NamedTextColor.GRAY)))).appendNewline()
|
||||||
|
.append(Component.text("Features",NamedTextColor.GOLD)
|
||||||
|
.append(Component.text(":",NamedTextColor.WHITE))).appendNewline();
|
||||||
|
|
||||||
|
for (TrollFeature troll : trollRegistry) {
|
||||||
|
helpMessage = helpMessage.append(Text.format(Text.Pallet.NEUTRAL,"[{0}] - {1}: {2}",troll.getRating(),troll.getName(),troll.getDescription())).appendNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.getSize() < 1 || (args.getSize() == 1 && Objects.equals("info",args.get(0).toString()))) {
|
||||||
|
sender.sendMessage(helpMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String choice = args.get(0).toString();
|
||||||
|
TrollFeature troll = null;
|
||||||
|
|
||||||
|
for (TrollFeature abstractTroll : trollRegistry) {
|
||||||
|
if (!abstractTroll.getName().equals(choice)) continue;
|
||||||
|
troll = abstractTroll;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (troll == null) {
|
||||||
|
errorAny(sender,"You must pick a valid troll. {0} does not exist!",choice);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (troll instanceof AbstractWand wand) {
|
||||||
|
troll.execute(sender,null);
|
||||||
|
|
||||||
|
if (!(sender instanceof Player p)) {
|
||||||
|
warningAny(sender,"Wands can only be given to a player.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!p.hasPermission(wand.getUsePermission())) {
|
||||||
|
warningAny(sender,"You lack the permission to use this wand.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p.getInventory().addItem(wand.getWandItem().clone()).isEmpty()) {
|
||||||
|
errorAny(p, "Your inventory is full!");
|
||||||
|
} else {
|
||||||
|
success(p, Component.text("You have received a {0}"), wand.getWandItem().displayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String target = args.get(1).toString();
|
||||||
|
Player victim = Bukkit.getPlayer(target);
|
||||||
|
|
||||||
|
if (victim == null || !victim.isOnline()) {
|
||||||
|
errorAny(sender,"You must pick an online player. {0} is not online!",target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.getSize() >= 3 && Objects.equals("stop",args.get(2).toString())) {
|
||||||
|
troll.stop(sender,victim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
troll.execute(sender,victim);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCompletion(CommandSender sender, Command command, String label, Args args, CompletionBuilder b) {
|
||||||
|
List<String> extras = new ArrayList<>();
|
||||||
|
trollRegistry.forEach(extra -> extras.add(extra.getName()));
|
||||||
|
b.then(
|
||||||
|
b.arg(extras)
|
||||||
|
.then(
|
||||||
|
b.argOnlinePlayers()
|
||||||
|
.then(
|
||||||
|
b.arg("stop")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).then(
|
||||||
|
b.arg("info")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.events.QuickListener;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.inventory.InventoryCreativeEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
public class CreativeHotbarEvent implements QuickListener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onNBT(InventoryCreativeEvent e) {
|
||||||
|
if (e.getCursor().getItemMeta() == null) return;
|
||||||
|
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||||
|
if (e.getCursor() == null) return;
|
||||||
|
|
||||||
|
ItemStack i = e.getCursor();
|
||||||
|
|
||||||
|
if (i.getItemMeta() == null) return;
|
||||||
|
if (!i.hasItemMeta()) return;
|
||||||
|
|
||||||
|
if (CloneDupeCore.getInstance().getManager().io.config.nbtWhitelist.contains(p.getUniqueId().toString())) return;
|
||||||
|
if (new ItemCheck().passes(i)) return;
|
||||||
|
|
||||||
|
e.setCancelled(true);
|
||||||
|
|
||||||
|
ItemStack replacement = new ItemStack(i.getType());
|
||||||
|
ItemMeta meta = i.getItemMeta();
|
||||||
|
e.setCurrentItem(replacement);
|
||||||
|
e.getCursor().setItemMeta(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.events.QuickListener;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
public class GamemodeEvent implements QuickListener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onJoin(PlayerJoinEvent e) {
|
||||||
|
Player p = e.getPlayer();
|
||||||
|
if (p.isOp()) return;
|
||||||
|
|
||||||
|
p.setGameMode(GameMode.SURVIVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar;
|
||||||
|
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
import me.trouper.clonedupecore.data.io.NBTConfig;
|
||||||
|
|
||||||
|
public abstract class AbstractCheck<T> implements Data {
|
||||||
|
public NBTConfig config = getNBT();
|
||||||
|
public abstract boolean passes(T input);
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.entities;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.NBT;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.utils.InventoryUtils;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.misc.InventoryCheck;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.MerchantRecipe;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class EntityCheck extends AbstractCheck<Entity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(Entity entity) {
|
||||||
|
if (entity instanceof Item itemEntity) {
|
||||||
|
if (!new ItemCheck().passes(itemEntity.getItemStack())) {
|
||||||
|
Verbose.send("Entity failed check: Item not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Inventory inv = InventoryUtils.getInventory(entity);
|
||||||
|
if (inv != null && !new InventoryCheck().passes(inv)) {
|
||||||
|
Verbose.send("Entity inventory failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (entity instanceof Villager villager) {
|
||||||
|
for (MerchantRecipe recipe : villager.getRecipes()) {
|
||||||
|
if (!new ItemCheck().passes(recipe.getResult())) {
|
||||||
|
Verbose.send("Villager recipe failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entity instanceof Mob mob) {
|
||||||
|
if (!new EquipmentCheck().passes(mob)) {
|
||||||
|
Verbose.send("Mob equipment failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entity.getPassengers().isEmpty()) {
|
||||||
|
if (!config.allowRecursion) {
|
||||||
|
Verbose.send("Entity recursion not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Entity passenger : entity.getPassengers()) {
|
||||||
|
if (!passes(passenger)) {
|
||||||
|
Verbose.send("Entity passenger failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AtomicBoolean failsTiming = new AtomicBoolean(false);
|
||||||
|
NBT.get(entity, nbt -> {
|
||||||
|
if (nbt.hasTag("DeathTime") && nbt.getInteger("DeathTime") < 1) {
|
||||||
|
Verbose.send("Entity death time check failed.");
|
||||||
|
failsTiming.set(true);
|
||||||
|
}
|
||||||
|
if (nbt.hasTag("HurtTime") && nbt.getInteger("HurtTime") < 1) {
|
||||||
|
Verbose.send("Entity hurt time check failed.");
|
||||||
|
failsTiming.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (failsTiming.get()) {
|
||||||
|
Verbose.send("Entity timing check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.entities;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.EntitySnapshot;
|
||||||
|
|
||||||
|
public class EntitySnapshotCheck extends AbstractCheck<EntitySnapshot> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(EntitySnapshot input) {
|
||||||
|
Location loc = new Location(Bukkit.getWorlds().getFirst(), 0, 1000000, 0);
|
||||||
|
Entity temp = input.createEntity(loc);
|
||||||
|
boolean result = new EntityCheck().passes(temp);
|
||||||
|
Verbose.send("Temp Entity %s Entity Check", result ? "failed" : "passed");
|
||||||
|
temp.remove();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.entities;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class EquipmentCheck extends AbstractCheck<Mob> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(Mob mob) {
|
||||||
|
Verbose.send("Running mob check.");
|
||||||
|
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||||
|
if (mob.getEquipment().getItem(slot).isEmpty()) continue;
|
||||||
|
ItemStack item = mob.getEquipment().getItem(slot);
|
||||||
|
if (!new ItemCheck().passes(item)) {
|
||||||
|
Verbose.send("Equipment slot did not pass.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.items;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.bukkit.enchantments.Enchantment.MENDING;
|
||||||
|
|
||||||
|
public class EnchantmentCheck extends AbstractCheck<ItemStack> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(ItemStack input) {
|
||||||
|
return !hasIllegalEnchants(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasIllegalEnchants(ItemStack item) {
|
||||||
|
Verbose.send("Checking item for illegal enchants: ", item.getType().name());
|
||||||
|
if (item.hasItemMeta() && item.getItemMeta().hasEnchants()) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
Map<Enchantment, Integer> enchantments = meta.getEnchants();
|
||||||
|
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
|
||||||
|
Enchantment enchantment = entry.getKey();
|
||||||
|
int level = entry.getValue();
|
||||||
|
if (level > getNBT().globalMaxEnchant || isOverLimit(enchantment, level)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOverLimit(Enchantment enchantment, int level) {
|
||||||
|
int maxLevel = getNBT().globalMaxEnchant;
|
||||||
|
|
||||||
|
if (enchantment.equals(MENDING)) {
|
||||||
|
maxLevel = getNBT().maxMending;
|
||||||
|
} else if (enchantment.equals(Enchantment.UNBREAKING)) {
|
||||||
|
maxLevel = getNBT().maxUnbreaking;
|
||||||
|
} else if (enchantment.equals(Enchantment.VANISHING_CURSE)) {
|
||||||
|
maxLevel = getNBT().maxCurseOfVanishing;
|
||||||
|
} else if (enchantment.equals(Enchantment.BINDING_CURSE)) {
|
||||||
|
maxLevel = getNBT().maxCurseOfBinding;
|
||||||
|
} else if (enchantment.equals(Enchantment.AQUA_AFFINITY)) {
|
||||||
|
maxLevel = getNBT().maxAquaAffinity;
|
||||||
|
} else if (enchantment.equals(Enchantment.PROTECTION)) {
|
||||||
|
maxLevel = getNBT().maxProtection;
|
||||||
|
} else if (enchantment.equals(Enchantment.BLAST_PROTECTION)) {
|
||||||
|
maxLevel = getNBT().maxBlastProtection;
|
||||||
|
} else if (enchantment.equals(Enchantment.DEPTH_STRIDER)) {
|
||||||
|
maxLevel = getNBT().maxDepthStrider;
|
||||||
|
} else if (enchantment.equals(Enchantment.FEATHER_FALLING)) {
|
||||||
|
maxLevel = getNBT().maxFeatherFalling;
|
||||||
|
} else if (enchantment.equals(Enchantment.FIRE_PROTECTION)) {
|
||||||
|
maxLevel = getNBT().maxFireProtection;
|
||||||
|
} else if (enchantment.equals(Enchantment.FROST_WALKER)) {
|
||||||
|
maxLevel = getNBT().maxFrostWalker;
|
||||||
|
} else if (enchantment.equals(Enchantment.PROJECTILE_PROTECTION)) {
|
||||||
|
maxLevel = getNBT().maxProjectileProtection;
|
||||||
|
} else if (enchantment.equals(Enchantment.RESPIRATION)) {
|
||||||
|
maxLevel = getNBT().maxRespiration;
|
||||||
|
} else if (enchantment.equals(Enchantment.SOUL_SPEED)) {
|
||||||
|
maxLevel = getNBT().maxSoulSpeed;
|
||||||
|
} else if (enchantment.equals(Enchantment.THORNS)) {
|
||||||
|
maxLevel = getNBT().maxThorns;
|
||||||
|
} else if (enchantment.equals(Enchantment.SWEEPING_EDGE)) {
|
||||||
|
maxLevel = getNBT().maxSweepingEdge;
|
||||||
|
} else if (enchantment.equals(Enchantment.SWIFT_SNEAK)) {
|
||||||
|
maxLevel = getNBT().maxSwiftSneak;
|
||||||
|
} else if (enchantment.equals(Enchantment.BANE_OF_ARTHROPODS)) {
|
||||||
|
maxLevel = getNBT().maxBaneOfArthropods;
|
||||||
|
} else if (enchantment.equals(Enchantment.FIRE_ASPECT)) {
|
||||||
|
maxLevel = getNBT().maxFireAspect;
|
||||||
|
} else if (enchantment.equals(Enchantment.LOOTING)) {
|
||||||
|
maxLevel = getNBT().maxLooting;
|
||||||
|
} else if (enchantment.equals(Enchantment.IMPALING)) {
|
||||||
|
maxLevel = getNBT().maxImpaling;
|
||||||
|
} else if (enchantment.equals(Enchantment.KNOCKBACK)) {
|
||||||
|
maxLevel = getNBT().maxKnockback;
|
||||||
|
} else if (enchantment.equals(Enchantment.SHARPNESS)) {
|
||||||
|
maxLevel = getNBT().maxSharpness;
|
||||||
|
} else if (enchantment.equals(Enchantment.SMITE)) {
|
||||||
|
maxLevel = getNBT().maxSmite;
|
||||||
|
} else if (enchantment.equals(Enchantment.CHANNELING)) {
|
||||||
|
maxLevel = getNBT().maxChanneling;
|
||||||
|
} else if (enchantment.equals(Enchantment.FLAME)) {
|
||||||
|
maxLevel = getNBT().maxFlame;
|
||||||
|
} else if (enchantment.equals(Enchantment.INFINITY)) {
|
||||||
|
maxLevel = getNBT().maxInfinity;
|
||||||
|
} else if (enchantment.equals(Enchantment.LOYALTY)) {
|
||||||
|
maxLevel = getNBT().maxLoyalty;
|
||||||
|
} else if (enchantment.equals(Enchantment.RIPTIDE)) {
|
||||||
|
maxLevel = getNBT().maxRiptide;
|
||||||
|
} else if (enchantment.equals(Enchantment.MULTISHOT)) {
|
||||||
|
maxLevel = getNBT().maxMultishot;
|
||||||
|
} else if (enchantment.equals(Enchantment.PIERCING)) {
|
||||||
|
maxLevel = getNBT().maxPiercing;
|
||||||
|
} else if (enchantment.equals(Enchantment.POWER)) {
|
||||||
|
maxLevel = getNBT().maxPower;
|
||||||
|
} else if (enchantment.equals(Enchantment.PUNCH)) {
|
||||||
|
maxLevel = getNBT().maxPunch;
|
||||||
|
} else if (enchantment.equals(Enchantment.QUICK_CHARGE)) {
|
||||||
|
maxLevel = getNBT().maxQuickCharge;
|
||||||
|
} else if (enchantment.equals(Enchantment.EFFICIENCY)) {
|
||||||
|
maxLevel = getNBT().maxEfficiency;
|
||||||
|
} else if (enchantment.equals(Enchantment.FORTUNE)) {
|
||||||
|
maxLevel = getNBT().maxFortune;
|
||||||
|
} else if (enchantment.equals(Enchantment.LUCK_OF_THE_SEA)) {
|
||||||
|
maxLevel = getNBT().maxLuckOfTheSea;
|
||||||
|
} else if (enchantment.equals(Enchantment.LURE)) {
|
||||||
|
maxLevel = getNBT().maxLure;
|
||||||
|
} else if (enchantment.equals(Enchantment.SILK_TOUCH)) {
|
||||||
|
maxLevel = getNBT().maxSilkTouch;
|
||||||
|
} else if (enchantment.equals(Enchantment.BREACH)) {
|
||||||
|
maxLevel = getNBT().maxBreach;
|
||||||
|
} else if (enchantment.equals(Enchantment.DENSITY)) {
|
||||||
|
maxLevel = getNBT().maxDensity;
|
||||||
|
} else if (enchantment.equals(Enchantment.WIND_BURST)) {
|
||||||
|
maxLevel = getNBT().maxWindBurst;
|
||||||
|
}
|
||||||
|
|
||||||
|
return level > maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.items;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.NBT;
|
||||||
|
import de.tr7zw.nbtapi.iface.ReadWriteNBT;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.utils.InventoryUtils;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.misc.BlockStateCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.misc.InventoryCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.nbt.ComponentCheck;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ItemCheck extends AbstractCheck<ItemStack> {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(ItemStack item) {
|
||||||
|
try {
|
||||||
|
return scan(item);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
CloneDupeCore.getInstance().getLogger().warning("Caught an exception while handling an item check: " + Arrays.toString(ex.getStackTrace()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean scan(ItemStack item) {
|
||||||
|
Verbose.send("Checking item: " + item.getType().name());
|
||||||
|
|
||||||
|
// No metadata? Nothing to check.
|
||||||
|
if (item.getItemMeta() == null) {
|
||||||
|
Verbose.send("Item passes because it has no metadata.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new MetaCheck().passes(item)) {
|
||||||
|
Verbose.send("Item failed metadata check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NBT-based checks
|
||||||
|
ReadWriteNBT nbt = NBT.itemStackToNBT(item);
|
||||||
|
ReadWriteNBT components = nbt.getCompound("components");
|
||||||
|
if (components != null) {
|
||||||
|
if (!new ComponentCheck().passes(components)) {
|
||||||
|
Verbose.send("Components check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn egg checks.
|
||||||
|
if (!new SpawnEggCheck().passes(item)) {
|
||||||
|
Verbose.send("Spawn egg check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new BlockStateCheck().passes(item)) {
|
||||||
|
Verbose.send("Block State check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for an inventory inside the item.
|
||||||
|
Inventory inv = InventoryUtils.getInventory(item);
|
||||||
|
if (inv != null) {
|
||||||
|
Verbose.send("Item contains an inventory: " + inv);
|
||||||
|
if (!new InventoryCheck().passes(inv)) {
|
||||||
|
Verbose.send("Item failed inventory check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Verbose.send("Item passed all checks.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.items;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
|
import org.bukkit.inventory.meta.BundleMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
public class MetaCheck extends AbstractCheck<ItemStack> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
// Name, lore, potion, attribute and enchantment checks.
|
||||||
|
if (!config.allowName && meta.hasDisplayName()) {
|
||||||
|
Verbose.send("Custom names not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.allowLore && meta.hasLore()) {
|
||||||
|
Verbose.send("Custom lore not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.allowBooks && meta instanceof BookMeta) {
|
||||||
|
Verbose.send("Item failed book check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.allowPotions &&
|
||||||
|
(item.getType().equals(Material.POTION) ||
|
||||||
|
item.getType().equals(Material.SPLASH_POTION) ||
|
||||||
|
item.getType().equals(Material.LINGERING_POTION))) {
|
||||||
|
Verbose.send("Potions not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.allowAttributes && meta.hasAttributeModifiers()) {
|
||||||
|
Verbose.send("Attribute modifiers not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (config.globalMaxEnchant != 0 && new EnchantmentCheck().hasIllegalEnchants(item)) {
|
||||||
|
Verbose.send("Illegal enchantments found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Bundle check – recursively check the contained items.
|
||||||
|
if (item.getType().name().contains("_BUNDLE") && meta instanceof BundleMeta bm) {
|
||||||
|
for (ItemStack bundleItem : bm.getItems()) {
|
||||||
|
if (!passes(bundleItem)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.items;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.NBT;
|
||||||
|
import kotlin.Pair;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.CloneDupeCore;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RateLimitCheck extends AbstractCheck<Pair<Player,ItemStack>> {
|
||||||
|
|
||||||
|
public static Map<UUID, Integer> dataUsed = new HashMap<>();
|
||||||
|
public static Map<UUID, Integer> itemsUsed = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(Pair<Player,ItemStack> input) {
|
||||||
|
Player player = input.getFirst();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
ItemStack item = input.getSecond();
|
||||||
|
|
||||||
|
return itemLimit(uuid,item) && dataLimit(uuid,item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean itemLimit(UUID uuid, ItemStack item) {
|
||||||
|
int currentUsed = itemsUsed.getOrDefault(uuid,0);
|
||||||
|
Verbose.send("Current Player used items: " + currentUsed);
|
||||||
|
currentUsed++;
|
||||||
|
itemsUsed.put(uuid,currentUsed);
|
||||||
|
return currentUsed <= config.rateLimit.rateLimitItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean dataLimit(UUID uuid, ItemStack item) {
|
||||||
|
int currentData = dataUsed.getOrDefault(uuid,0);
|
||||||
|
|
||||||
|
Verbose.send("Current Player used data: " + currentData);
|
||||||
|
try {
|
||||||
|
int itemData = NBT.readNbt(item).toString().length();
|
||||||
|
Verbose.send("Item data: " + itemData);
|
||||||
|
if (currentData < config.rateLimit.maxOverhead) currentData += itemData;
|
||||||
|
} catch (Exception e) {
|
||||||
|
CloneDupeCore.getInstance().getLogger().warning("Could not determine size of item. Blocking.");
|
||||||
|
CloneDupeCore.getInstance().getLogger().warning(Arrays.toString(e.getStackTrace()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataUsed.put(uuid,currentData);
|
||||||
|
|
||||||
|
Verbose.send("New Player used data: " + currentData);
|
||||||
|
|
||||||
|
return currentData <= config.rateLimit.rateLimitBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decayData() {
|
||||||
|
for (UUID uuid : dataUsed.keySet()) {
|
||||||
|
int currentData = dataUsed.get(uuid);
|
||||||
|
if (currentData > 0) {
|
||||||
|
currentData -= config.rateLimit.byteDecay;
|
||||||
|
dataUsed.put(uuid, Math.max(0, currentData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decayItems() {
|
||||||
|
for (UUID uuid : itemsUsed.keySet()) {
|
||||||
|
int currentItems = itemsUsed.get(uuid);
|
||||||
|
if (currentItems > 0) {
|
||||||
|
currentItems -= config.rateLimit.itemDecay;
|
||||||
|
itemsUsed.put(uuid, Math.max(0, currentItems));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.items;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.NBT;
|
||||||
|
import de.tr7zw.nbtapi.iface.ReadWriteNBT;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.entities.EntitySnapshotCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.nbt.EntityDataCheck;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.SpawnEggMeta;
|
||||||
|
|
||||||
|
public class SpawnEggCheck extends AbstractCheck<ItemStack> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(ItemStack item) {
|
||||||
|
Verbose.send("Running spawn egg checks on item: ",item.getType().name());
|
||||||
|
if (!item.getType().name().toLowerCase().contains("spawn_egg")) return true;
|
||||||
|
if (!SpawnEggCheck.entityMatches(item)) {
|
||||||
|
Verbose.send("Spawn egg entity doesn't match item type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ReadWriteNBT nbt = NBT.itemStackToNBT(item);
|
||||||
|
ReadWriteNBT components = nbt.getCompound("components");
|
||||||
|
if (components != null) {
|
||||||
|
var entityData = components.getCompound("minecraft:entity_data");
|
||||||
|
if (!new EntityDataCheck().passes(entityData)) {
|
||||||
|
Verbose.send("Spawn egg entity data check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.hasItemMeta() && item.getItemMeta() instanceof SpawnEggMeta sem) {
|
||||||
|
if (sem.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(sem.getSpawnedEntity())) {
|
||||||
|
Verbose.send("Spawn egg entity snapshot check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean entityMatches(ItemStack item) {
|
||||||
|
if (item.hasItemMeta() && item.getItemMeta() instanceof SpawnEggMeta sem) {
|
||||||
|
String eggEntityName = item.getType().name().replace("_SPAWN_EGG", "");
|
||||||
|
return sem.getSpawnedEntity() != null &&
|
||||||
|
sem.getSpawnedEntity().getEntityType().name().equals(eggEntityName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.misc;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.entities.EntitySnapshotCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.*;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.spawner.TrialSpawnerConfiguration;
|
||||||
|
|
||||||
|
public class BlockStateCheck extends AbstractCheck<ItemStack> {
|
||||||
|
@Override
|
||||||
|
public boolean passes(ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
|
||||||
|
if (!(meta instanceof BlockStateMeta blockStateMeta)) {
|
||||||
|
Verbose.send("Item passes due to not being a block state meta");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getType().name().contains("CAMPFIRE") ) {
|
||||||
|
BlockState bs = blockStateMeta.getBlockState();
|
||||||
|
if (bs instanceof Campfire campfire) {
|
||||||
|
for (int slot = 0; slot < 4; slot++) {
|
||||||
|
ItemStack campfireItem = campfire.getItem(slot);
|
||||||
|
if (campfireItem != null && !new ItemCheck().passes(campfireItem)) {
|
||||||
|
Verbose.send("Campfire item failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lectern and Chiseled Bookshelf check (by validating their inventories).
|
||||||
|
if (item.getType().equals(Material.LECTERN)) {
|
||||||
|
BlockState bs = blockStateMeta.getBlockState();
|
||||||
|
if (bs instanceof Lectern lectern) {
|
||||||
|
if (!new InventoryCheck().passes(lectern.getInventory())) {
|
||||||
|
Verbose.send("Lectern inventory failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.getType().equals(Material.CHISELED_BOOKSHELF)) {
|
||||||
|
BlockState bs = blockStateMeta.getBlockState();
|
||||||
|
if (bs instanceof ChiseledBookshelf bookshelf) {
|
||||||
|
if (!new InventoryCheck().passes(bookshelf.getInventory())) {
|
||||||
|
Verbose.send("Chiseled bookshelf inventory failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawner check.
|
||||||
|
if (item.getType().equals(Material.SPAWNER)) {
|
||||||
|
BlockState bs = blockStateMeta.getBlockState();
|
||||||
|
if (bs instanceof CreatureSpawner spawner) {
|
||||||
|
if (spawner.getSpawnedEntity() != null) {
|
||||||
|
if (spawner.getSpawnedEntity().getEntityType().equals(EntityType.FALLING_BLOCK) ||
|
||||||
|
spawner.getSpawnedEntity().getEntityType().equals(EntityType.COMMAND_BLOCK_MINECART)) {
|
||||||
|
Verbose.send("Spawner contains disallowed entity type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!new EntitySnapshotCheck().passes(spawner.getSpawnedEntity())) {
|
||||||
|
Verbose.send("Spawner entity snapshot check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trial Spawner check.
|
||||||
|
if (item.getType() == Material.TRIAL_SPAWNER) {
|
||||||
|
BlockState bs = blockStateMeta.getBlockState();
|
||||||
|
if (bs instanceof TrialSpawner spawner) {
|
||||||
|
Verbose.send("Running trial spawner check.");
|
||||||
|
if (spawner.getNormalConfiguration() != null) {
|
||||||
|
TrialSpawnerConfiguration config = spawner.getNormalConfiguration();
|
||||||
|
if (config.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(config.getSpawnedEntity())) {
|
||||||
|
Verbose.send("Trial Spawner failed check: Normal entity snapshot not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spawner.getOminousConfiguration() != null) {
|
||||||
|
TrialSpawnerConfiguration config = spawner.getOminousConfiguration();
|
||||||
|
if (config.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(config.getSpawnedEntity())) {
|
||||||
|
Verbose.send("Trial Spawner failed check: Ominous entity snapshot not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.misc;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.utils.InventoryUtils;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class InventoryCheck extends AbstractCheck<Inventory> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(Inventory inv) {
|
||||||
|
Verbose.send("Running Inventory Check");
|
||||||
|
|
||||||
|
for (ItemStack i : inv.getContents()) {
|
||||||
|
if (i == null || i.getType().isAir()) continue;
|
||||||
|
if (!new ItemCheck().passes(i)) {
|
||||||
|
Verbose.send("Inventory item failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Inventory subInventory = InventoryUtils.getInventory(i);
|
||||||
|
if (subInventory != null && !config.allowRecursion) {
|
||||||
|
Verbose.send("Recursion is disabled. Failing check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (subInventory != null && !passes(subInventory)) {
|
||||||
|
Verbose.send("Sub-inventory failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Verbose.send("Inventory passed all checks.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.nbt;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.iface.ReadWriteNBT;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
|
||||||
|
public class ComponentCheck extends AbstractCheck<ReadWriteNBT> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passes(ReadWriteNBT components) {
|
||||||
|
Verbose.send("Checking Consumable & tool");
|
||||||
|
if (!config.allowCustomConsumables && components.getCompound("minecraft:consumable") != null) {
|
||||||
|
Verbose.send("Item is consumable and not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.allowCustomTools && components.getCompound("minecraft:tool") != null) {
|
||||||
|
Verbose.send("Item is custom tool and not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Verbose.send("Checking Entity data");
|
||||||
|
|
||||||
|
ReadWriteNBT entityData = components.getCompound("minecraft:entity_data");
|
||||||
|
if (!new EntityDataCheck().passes(entityData)) {
|
||||||
|
Verbose.send("Entity Data Check Failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package me.trouper.clonedupecore.server.events.hotbar.nbt;
|
||||||
|
|
||||||
|
import de.tr7zw.nbtapi.NBT;
|
||||||
|
import de.tr7zw.nbtapi.iface.ReadWriteNBT;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.AbstractCheck;
|
||||||
|
import me.trouper.clonedupecore.server.events.hotbar.items.ItemCheck;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class EntityDataCheck extends AbstractCheck<ReadWriteNBT> {
|
||||||
|
@Override
|
||||||
|
public boolean passes(ReadWriteNBT entityData) {
|
||||||
|
if (entityData == null) {
|
||||||
|
Verbose.send("Entity Data check passed. There was no data.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriteNBT itemData = entityData.getCompound("Item");
|
||||||
|
if (itemData != null) {
|
||||||
|
Verbose.send("Entity data holds an item");
|
||||||
|
ItemStack heldItem = NBT.itemStackFromNBT(itemData);
|
||||||
|
if (heldItem != null && !new ItemCheck().passes(heldItem)) {
|
||||||
|
Verbose.send("Item contents failed check.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityData.hasTag("DeathTime") && entityData.getInteger("DeathTime") < 1) {
|
||||||
|
Verbose.send("Death time check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (entityData.hasTag("HurtTime") && entityData.getInteger("HurtTime") < 1) {
|
||||||
|
Verbose.send("Hurt time check failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Verbose.send("Entity Data check passed. There was no flagging.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.Main;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Freeze implements Main {
|
||||||
|
private static final Map<UUID, FrozenPlayer> FROZEN_PLAYERS = new HashMap<>();
|
||||||
|
|
||||||
|
public static void freezePlayer(OfflinePlayer player) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (!FROZEN_PLAYERS.containsKey(uuid)) {
|
||||||
|
FrozenPlayer frozen = new FrozenPlayer(main.getPlugin(), uuid);
|
||||||
|
FROZEN_PLAYERS.put(uuid, frozen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void thawPlayer(OfflinePlayer player) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
FrozenPlayer frozen = FROZEN_PLAYERS.remove(uuid);
|
||||||
|
if (frozen != null) {
|
||||||
|
frozen.thaw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FrozenPlayer {
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final Listener listener;
|
||||||
|
private boolean frozen;
|
||||||
|
|
||||||
|
public FrozenPlayer(JavaPlugin plugin, UUID uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.frozen = true;
|
||||||
|
|
||||||
|
this.listener = new Listener() {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
if (!event.getPlayer().getUniqueId().equals(uuid)) return;
|
||||||
|
if (!frozen) return;
|
||||||
|
|
||||||
|
if (!event.getFrom().toVector().equals(event.getTo().toVector())) {
|
||||||
|
event.setTo(event.getFrom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
if (!event.getPlayer().getUniqueId().equals(uuid)) return;
|
||||||
|
if (!frozen) return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerInteract(PlayerCommandPreprocessEvent event) {
|
||||||
|
if (!event.getPlayer().getUniqueId().equals(uuid)) return;
|
||||||
|
if (!frozen) return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDamage(EntityDamageByEntityEvent event) {
|
||||||
|
if (!event.getEntity().getUniqueId().equals(uuid)) return;
|
||||||
|
if (!frozen) return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDamage(EntityDamageByBlockEvent event) {
|
||||||
|
if (!event.getEntity().getUniqueId().equals(uuid)) return;
|
||||||
|
if (!frozen) return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Bukkit.getPluginManager().registerEvents(listener, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thaw() {
|
||||||
|
this.frozen = false;
|
||||||
|
HandlerList.unregisterAll(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFrozen() {
|
||||||
|
return frozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment;
|
||||||
|
|
||||||
|
import club.minnced.discord.webhook.WebhookClient;
|
||||||
|
import club.minnced.discord.webhook.WebhookClientBuilder;
|
||||||
|
import club.minnced.discord.webhook.send.WebhookEmbed;
|
||||||
|
import club.minnced.discord.webhook.send.WebhookEmbedBuilder;
|
||||||
|
import litebans.api.Database;
|
||||||
|
import litebans.api.Entry;
|
||||||
|
import me.trouper.alias.server.Main;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class LiteBansManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all ban entries for a specific player
|
||||||
|
*/
|
||||||
|
public List<WrappedEntry> getPlayerBans(OfflinePlayer player) {
|
||||||
|
List<WrappedEntry> bans = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = Database.get().prepareStatement(
|
||||||
|
"SELECT * FROM {bans} WHERE uuid = ? ORDER BY time DESC"
|
||||||
|
);
|
||||||
|
statement.setString(1, player.getUniqueId().toString());
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
bans.add(new WrappedEntry(rs));
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.close();
|
||||||
|
statement.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return bans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ban entries for a specific player and template
|
||||||
|
* @param template a short representing where in the template.yml list the item is.
|
||||||
|
*/
|
||||||
|
public List<WrappedEntry> getPlayerBansByTemplate(OfflinePlayer player, short template) {
|
||||||
|
List<WrappedEntry> bans = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = Database.get().prepareStatement(
|
||||||
|
"SELECT * FROM {bans} WHERE uuid = ? AND template = ? ORDER BY time DESC"
|
||||||
|
);
|
||||||
|
statement.setString(1, player.getUniqueId().toString());
|
||||||
|
statement.setShort(2, template);
|
||||||
|
ResultSet result = statement.executeQuery();
|
||||||
|
|
||||||
|
while (result.next()) {
|
||||||
|
bans.add(new WrappedEntry(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.close();
|
||||||
|
statement.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return bans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the count of bans for a specific template
|
||||||
|
* @param template a short representing where in the template.yml list the item is.
|
||||||
|
*/
|
||||||
|
public int getBanCountByTemplate(OfflinePlayer player, short template) {
|
||||||
|
return getPlayerBansByTemplate(player, template).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if player is currently banned
|
||||||
|
*/
|
||||||
|
public boolean isPlayerBanned(OfflinePlayer player) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = Database.get().prepareStatement(
|
||||||
|
"SELECT COUNT(*) FROM {bans} WHERE uuid = ? AND active = 1"
|
||||||
|
);
|
||||||
|
statement.setString(1, player.getUniqueId().toString());
|
||||||
|
ResultSet result = statement.executeQuery();
|
||||||
|
|
||||||
|
if (result.next()) {
|
||||||
|
return result.getInt(1) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.close();
|
||||||
|
statement.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get active ban for player
|
||||||
|
*/
|
||||||
|
public WrappedEntry getActiveBan(OfflinePlayer player) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = Database.get().prepareStatement(
|
||||||
|
"SELECT * FROM {bans} WHERE uuid = ? AND active = 1 ORDER BY time DESC LIMIT 1"
|
||||||
|
);
|
||||||
|
statement.setString(1, player.getUniqueId().toString());
|
||||||
|
ResultSet result = statement.executeQuery();
|
||||||
|
|
||||||
|
if (result.next()) {
|
||||||
|
WrappedEntry entry = new WrappedEntry(result);
|
||||||
|
result.close();
|
||||||
|
statement.close();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.close();
|
||||||
|
statement.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a ban using LiteBans template system
|
||||||
|
*/
|
||||||
|
public void executeBan(OfflinePlayer player, String template, CommandSender executor) {
|
||||||
|
Bukkit.getScheduler().runTask(Main.main.getPlugin(),()-> {
|
||||||
|
Bukkit.dispatchCommand(executor,
|
||||||
|
String.format("litebans:ban %s %s -s", player.getName(), template));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment;
|
||||||
|
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public class WrappedEntry implements Data {
|
||||||
|
|
||||||
|
private final long dateStart;
|
||||||
|
private final long dateEnd;
|
||||||
|
private final String reason;
|
||||||
|
private final String template;
|
||||||
|
private final boolean active;
|
||||||
|
private final boolean permanent;
|
||||||
|
|
||||||
|
public WrappedEntry(long dateStart, long dateEnd, String reason, boolean active, boolean permanent) {
|
||||||
|
this.dateStart = dateStart;
|
||||||
|
this.dateEnd = dateEnd;
|
||||||
|
this.reason = reason;
|
||||||
|
this.active = active;
|
||||||
|
this.permanent = permanent;
|
||||||
|
this.template = "none!";
|
||||||
|
}
|
||||||
|
|
||||||
|
public WrappedEntry(ResultSet rs) throws SQLException {
|
||||||
|
String reason = rs.getString("reason");
|
||||||
|
long time = rs.getLong("time");
|
||||||
|
long until = rs.getLong("until");
|
||||||
|
boolean active = rs.getBoolean("active");
|
||||||
|
short template = rs.getShort("template");
|
||||||
|
|
||||||
|
this.reason = reason;
|
||||||
|
this.dateStart = time;
|
||||||
|
this.dateEnd = until;
|
||||||
|
this.active = active;
|
||||||
|
this.permanent = until <= 0;
|
||||||
|
this.template = getConfig().banTemplates.get(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDateStart() {
|
||||||
|
return dateStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDateEnd() {
|
||||||
|
return dateEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPermanent() {
|
||||||
|
return permanent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.Freeze;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.entity.Arrow;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.FallingBlock;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AnvilAnimation extends PunishmentAnimation {
|
||||||
|
|
||||||
|
private final Set<FallingBlock> spawnedAnvils = new HashSet<>();
|
||||||
|
private boolean spawned = false;
|
||||||
|
private boolean white = false;
|
||||||
|
|
||||||
|
public AnvilAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
super(plugin, player, finishTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(int ticksElapsed) {
|
||||||
|
Freeze.freezePlayer(player);
|
||||||
|
if (!spawned) {
|
||||||
|
spawnAnvilRing();
|
||||||
|
DisplayUtils.ring(player.getLocation().add(0,10,0),5,1,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.CLOUD)
|
||||||
|
.speed(0.07F)
|
||||||
|
.count(10)
|
||||||
|
.offset(0.5,0.2,0.5)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
spawned = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
DisplayUtils.ring(player.getLocation().add(0,0.1,0), (double)i/2D,0.5,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(finalI % 2 == 0 ? Color.RED : Color.WHITE,2F))
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
spawnedAnvils.removeIf(block -> block.isDead() || block.isOnGround());
|
||||||
|
|
||||||
|
if (ticksElapsed > 20 && (spawnedAnvils.isEmpty() || ticksElapsed > 300)) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnAnvilRing() {
|
||||||
|
Location center = player.getLocation().add(0, 10, 0);
|
||||||
|
World world = player.getWorld();
|
||||||
|
|
||||||
|
int amount = 12;
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{
|
||||||
|
double angle = 2 * Math.PI * finalI / amount;
|
||||||
|
int RADIUS = 5;
|
||||||
|
double x = center.getX() + RADIUS * Math.cos(angle);
|
||||||
|
double z = center.getZ() + RADIUS * Math.sin(angle);
|
||||||
|
Location spawnLoc = new Location(world, x, center.getY(), z);
|
||||||
|
|
||||||
|
FallingBlock anvil = world.spawn(spawnLoc, FallingBlock.class);
|
||||||
|
anvil.setBlockData(Material.ANVIL.createBlockData());
|
||||||
|
anvil.setCancelDrop(true);
|
||||||
|
anvil.setHurtEntities(false);
|
||||||
|
|
||||||
|
Vector velocity = player.getLocation().toVector().subtract(spawnLoc.toVector()).normalize().multiply(0.7);
|
||||||
|
velocity.setY(-0.3);
|
||||||
|
anvil.setVelocity(velocity);
|
||||||
|
|
||||||
|
spawnedAnvils.add(anvil);
|
||||||
|
},i*2);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
Freeze.thawPlayer(player);
|
||||||
|
for (FallingBlock block : spawnedAnvils) {
|
||||||
|
if (!block.isDead()) {
|
||||||
|
block.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawnedAnvils.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.utils.VectorUtils;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.Freeze;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Guardian;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GwenAnimation extends PunishmentAnimation {
|
||||||
|
|
||||||
|
private final List<Entity> guardians = new ArrayList<>();
|
||||||
|
int guardianCount = 4;
|
||||||
|
double animationTicks = 20 * 8;
|
||||||
|
|
||||||
|
public GwenAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
super(plugin, player, finishTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(int ticksElapsed) {
|
||||||
|
Freeze.freezePlayer(player);
|
||||||
|
|
||||||
|
Location head = player.getEyeLocation();
|
||||||
|
Location center = head.clone().add(0, 3, 0);
|
||||||
|
World w = head.getWorld();
|
||||||
|
|
||||||
|
if (ticksElapsed > animationTicks) {
|
||||||
|
head.getWorld().spawnParticle(Particle.EXPLOSION_EMITTER,head,10,1,1,1);
|
||||||
|
head.getWorld().strikeLightningEffect(head);
|
||||||
|
|
||||||
|
Verbose.send("Closing G.W.E.N. animation");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double animationPrecent = ticksElapsed / animationTicks;
|
||||||
|
double radius = 4 - 3 * animationPrecent;
|
||||||
|
double angleStep = 2 * Math.PI / guardianCount;
|
||||||
|
double rotationSpeed = animationPrecent / 2;
|
||||||
|
|
||||||
|
if (ticksElapsed == 1) {
|
||||||
|
for (int i = 0; i < guardianCount; i++) {
|
||||||
|
double angle = i * angleStep;
|
||||||
|
double x = Math.cos(angle) * radius;
|
||||||
|
double z = Math.sin(angle) * radius;
|
||||||
|
Location loc = center.clone().add(x, 0, z);
|
||||||
|
Vector look = center.toVector().subtract(loc.toVector());
|
||||||
|
float[] angles = VectorUtils.toAngles(look);
|
||||||
|
w.spawn(loc, Guardian.class, (guardian) -> {
|
||||||
|
guardians.add(guardian);
|
||||||
|
guardian.setRotation(angles[0], angles[1]);
|
||||||
|
guardian.setTarget(player);
|
||||||
|
guardian.setAI(false);
|
||||||
|
guardian.setInvulnerable(true);
|
||||||
|
guardian.setLaser(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < guardians.size(); i++) {
|
||||||
|
Entity entity = guardians.get(i);
|
||||||
|
if (entity == null || entity.isDead()) continue;
|
||||||
|
|
||||||
|
double angle = i * angleStep + rotationSpeed * ticksElapsed;
|
||||||
|
double x = Math.cos(angle) * radius;
|
||||||
|
double z = Math.sin(angle) * radius;
|
||||||
|
Location newLoc = center.clone().add(x, 0, z);
|
||||||
|
|
||||||
|
Vector look = center.toVector().subtract(newLoc.toVector());
|
||||||
|
float[] angles = VectorUtils.toAngles(look);
|
||||||
|
|
||||||
|
entity.teleport(newLoc);
|
||||||
|
entity.setRotation(angles[0], angles[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
Freeze.thawPlayer(player);
|
||||||
|
|
||||||
|
for (Entity entity : guardians) {
|
||||||
|
if (entity == null) continue;
|
||||||
|
entity.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
guardians.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.tracing.BlockDisplayRaytracer;
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.Freeze;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.FallingBlock;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public class LaserAnimation extends PunishmentAnimation {
|
||||||
|
public LaserAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
super(plugin, player, finishTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(int ticksElapsed) {
|
||||||
|
Freeze.freezePlayer(player);
|
||||||
|
Location target = player.getEyeLocation();
|
||||||
|
Location center = player.getLocation();
|
||||||
|
|
||||||
|
if (ticksElapsed > 20 * 2) {
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed == 1) {
|
||||||
|
DisplayUtils.sphereWave(target,8,1,1,(point)->{
|
||||||
|
point.getWorld().spawnParticle(Particle.SMOKE,point,2,0.5,0.5,0.5,0.01);
|
||||||
|
point.getWorld().spawnParticle(Particle.FLAME,point,2,0.5,0.5,0.5,0.01);
|
||||||
|
});
|
||||||
|
|
||||||
|
DisplayUtils.wave(player.getLocation().clone().add(0,0.5,0),5,point -> {
|
||||||
|
Block block = point.getWorld().getBlockAt(point.clone().subtract(0,2,0));
|
||||||
|
point.getWorld().spawn(point, FallingBlock.class,(launched)->{
|
||||||
|
launched.setVelocity(point.toVector().subtract(center.toVector()).normalize().multiply(0.4).setY(1));
|
||||||
|
launched.setBlockData(block.getBlockData());
|
||||||
|
launched.setBlockState(block.getState());
|
||||||
|
launched.setCancelDrop(true);
|
||||||
|
launched.setVisualFire(true);
|
||||||
|
});
|
||||||
|
point.getWorld().spawnParticle(Particle.EXPLOSION,point,1);
|
||||||
|
point.getWorld().spawnParticle(Particle.BLOCK,point,1,block.getBlockData());
|
||||||
|
},1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Location orbit = player.getLocation().clone().add(200-ticksElapsed*2,0,100);
|
||||||
|
orbit.setY(315);
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask(main.getPlugin(),()->{
|
||||||
|
BlockDisplayRaytracer.trace(Material.SMOOTH_QUARTZ,target,orbit,0.5,2);
|
||||||
|
BlockDisplayRaytracer.trace(Material.RED_STAINED_GLASS,target,orbit,1 + main.random().nextDouble(),2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
Freeze.thawPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.Freeze;
|
||||||
|
import me.trouper.clonedupecore.server.trolls.DragTrollWand;
|
||||||
|
import me.trouper.clonedupecore.utils.PlayerUtils;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.damage.DamageSource;
|
||||||
|
import org.bukkit.damage.DamageType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public class LightningAnimation extends PunishmentAnimation {
|
||||||
|
public LightningAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
super(plugin, player, finishTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(int ticksElapsed) {
|
||||||
|
Freeze.freezePlayer(player);
|
||||||
|
Location cloudCenter = player.getLocation().clone().add(0,10,0);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.CLOUD)
|
||||||
|
.offset(3, 0.8, 3)
|
||||||
|
.count(200)
|
||||||
|
.spawn(cloudCenter);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.ELECTRIC_SPARK)
|
||||||
|
.count(10)
|
||||||
|
.offset(0.3,1,0.3)
|
||||||
|
.spawn(player.getLocation().clone().add(0,1,0));
|
||||||
|
|
||||||
|
double x = main.randomizer().getRandomDouble(-4,4);
|
||||||
|
double z = main.randomizer().getRandomDouble(-4,4);
|
||||||
|
Location lightningLoc = cloudCenter.clone().add(x,0,z);
|
||||||
|
|
||||||
|
if (ticksElapsed > 40) {
|
||||||
|
PlayerUtils.instantTrueDamage(player, DamageSource.builder(DamageType.LIGHTNING_BOLT).build(),0.001);
|
||||||
|
if (ticksElapsed % 15 == 0) {
|
||||||
|
new SoundPlayer(Sound.ENTITY_LIGHTNING_BOLT_IMPACT,1,1).playAt(player.getLocation(),30);
|
||||||
|
new SoundPlayer(Sound.ENTITY_LIGHTNING_BOLT_THUNDER,1,1).playAt(lightningLoc,30);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
DragTrollWand.drawLightning(lightningLoc,player.getEyeLocation(), Material.BLUE_ICE, Material.LIGHT_BLUE_STAINED_GLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed > 120) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
Freeze.thawPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.clonedupecore.server.punishment.Freeze;
|
||||||
|
import me.trouper.clonedupecore.server.trolls.DragTrollWand;
|
||||||
|
import me.trouper.clonedupecore.server.trolls.MatrixTroll;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Display;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.TextDisplay;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class MatrixAnimation extends PunishmentAnimation{
|
||||||
|
public MatrixAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
super(plugin, player, finishTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Entity, ScheduledTask> cleanupList = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(int ticksElapsed) {
|
||||||
|
if (ticksElapsed > 60) {
|
||||||
|
player.getWorld().strikeLightningEffect(player.getLocation());
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
Location center = player.getLocation().clone().add(0,1,0);
|
||||||
|
center.setYaw(0);
|
||||||
|
center.setPitch(0);
|
||||||
|
|
||||||
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
DragTrollWand.drawLightning(center,center.clone().add(
|
||||||
|
random.nextDouble(-8,8),
|
||||||
|
random.nextDouble(0,8),
|
||||||
|
random.nextDouble(-8,8)
|
||||||
|
), Material.LIME_CONCRETE,Material.LIME_STAINED_GLASS);
|
||||||
|
|
||||||
|
if (ticksElapsed != 1) return;
|
||||||
|
Freeze.freezePlayer(player);
|
||||||
|
|
||||||
|
DisplayUtils.sphereWave(center,5,0.5,2,(point)->{
|
||||||
|
TextDisplay display = point.getWorld().spawn(point,TextDisplay.class,(td)->{
|
||||||
|
td.text(MatrixTroll.generateMatrix(2,2));
|
||||||
|
td.setBillboard(Display.Billboard.FIXED);
|
||||||
|
float yawDegrees = random.nextFloat() * 360;
|
||||||
|
float yawRadians = (float) Math.toRadians(yawDegrees);
|
||||||
|
AxisAngle4f angle = new AxisAngle4f(yawRadians,0,1,0);
|
||||||
|
td.setTransformation(new Transformation(
|
||||||
|
new Vector3f(0,0,0),
|
||||||
|
angle,
|
||||||
|
new Vector3f(3,3,3),
|
||||||
|
new AxisAngle4f(0,0,0,0)
|
||||||
|
));
|
||||||
|
td.setBackgroundColor(Color.fromARGB(0xFF000000));
|
||||||
|
td.setBrightness(new Display.Brightness(15,15));
|
||||||
|
});
|
||||||
|
|
||||||
|
ScheduledTask task = display.getScheduler().runAtFixedRate(main.getPlugin(),(t)->{
|
||||||
|
float yawDegrees = random.nextFloat() * 360;
|
||||||
|
float yawRadians = (float) Math.toRadians(yawDegrees);
|
||||||
|
AxisAngle4f angle = new AxisAngle4f(yawRadians,0,1,0);
|
||||||
|
display.setTransformation(new Transformation(
|
||||||
|
new Vector3f(0,0,0),
|
||||||
|
angle,
|
||||||
|
new Vector3f(1,1,1),
|
||||||
|
new AxisAngle4f(0,0,0,0)
|
||||||
|
));
|
||||||
|
display.setInterpolationDuration(4);
|
||||||
|
display.text(MatrixTroll.generateMatrix(9,5));
|
||||||
|
},null,1,5);
|
||||||
|
cleanupList.put(display,task);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
Freeze.thawPlayer(player);
|
||||||
|
for (Map.Entry<Entity, ScheduledTask> entry : cleanupList.entrySet()) {
|
||||||
|
entry.getValue().cancel();
|
||||||
|
entry.getKey().remove();
|
||||||
|
}
|
||||||
|
cleanupList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package me.trouper.clonedupecore.server.punishment.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.Main;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
public abstract class PunishmentAnimation extends BukkitRunnable implements Closeable, Main {
|
||||||
|
|
||||||
|
protected final JavaPlugin plugin;
|
||||||
|
protected final String playerName;
|
||||||
|
protected Player player;
|
||||||
|
protected int ticksElapsed = 0;
|
||||||
|
private boolean finished = false;
|
||||||
|
private final Runnable finishTask;
|
||||||
|
|
||||||
|
public PunishmentAnimation(JavaPlugin plugin, Player player, Runnable finishTask) {
|
||||||
|
if (player == null || !player.isOnline()) {
|
||||||
|
throw new IllegalStateException("Player must be online and non-null to start animation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.player = player;
|
||||||
|
this.playerName = player.getName();
|
||||||
|
this.finishTask = finishTask;
|
||||||
|
|
||||||
|
Verbose.send("Animation created, running task timer...");
|
||||||
|
runTaskTimer(plugin, 0L, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AnimationFactory {
|
||||||
|
PunishmentAnimation create(JavaPlugin plugin, Player player, Runnable onFinish);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (isFinished()) return;
|
||||||
|
|
||||||
|
this.player = Bukkit.getPlayerExact(playerName);
|
||||||
|
if (this.player == null || !this.player.isOnline()) {
|
||||||
|
Verbose.send("Finishing animation due to player logging off!");
|
||||||
|
finishAnimation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Bukkit.getScheduler().runTask(main.getPlugin(),()->{
|
||||||
|
tick(ticksElapsed++);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Verbose.send("An animation experienced an unexpected runtime exception while ticking.");
|
||||||
|
e.printStackTrace();
|
||||||
|
Bukkit.getScheduler().runTask(main.getPlugin(), this::finishAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void tick(int ticksElapsed);
|
||||||
|
|
||||||
|
protected abstract void cleanup();
|
||||||
|
|
||||||
|
private void finishAnimation() {
|
||||||
|
if (isFinished()) return;
|
||||||
|
finished = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
cancel();
|
||||||
|
} catch (IllegalStateException ignored) {}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
if (finishTask != null) {
|
||||||
|
try {
|
||||||
|
finishTask.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
finishAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished() {
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.Main;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public abstract class MaterialAnimation implements Main {
|
||||||
|
private final ValidMaterial material;
|
||||||
|
private final long loopDuration;
|
||||||
|
|
||||||
|
public MaterialAnimation(ValidMaterial material, long loopDuration) {
|
||||||
|
this.material = material;
|
||||||
|
this.loopDuration = loopDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidMaterial getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLoopDuration() {
|
||||||
|
return loopDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void tickMoving(Player player, Set<Player> viewers, long loopTime);
|
||||||
|
public abstract void tickStationary(Player player, Set<Player> viewers, long loopTime);
|
||||||
|
public abstract void onRemove(Player player);
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.Main;
|
||||||
|
import me.trouper.clonedupecore.data.Data;
|
||||||
|
import me.trouper.clonedupecore.utils.ArmorUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class TrimManager implements Main, Data {
|
||||||
|
private final Map<ValidMaterial, MaterialAnimation> animations = new EnumMap<>(ValidMaterial.class);
|
||||||
|
private final Map<UUID, ActiveTrim> activePlayers = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public void register(MaterialAnimation animation) {
|
||||||
|
animations.put(animation.getMaterial(), animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickPlayer(Player player) {
|
||||||
|
if (shouldHide(player)) return;
|
||||||
|
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
ValidMaterial currentMaterial = getActiveMaterial(player);
|
||||||
|
ActiveTrim active = activePlayers.get(uuid);
|
||||||
|
Location currentLocation = player.getLocation();
|
||||||
|
|
||||||
|
if (currentMaterial == null) {
|
||||||
|
if (activePlayers.containsKey(uuid)) {
|
||||||
|
animations.get(activePlayers.get(uuid).material).onRemove(player);
|
||||||
|
activePlayers.remove(uuid);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active != null && active.material == currentMaterial) {
|
||||||
|
active.ticks++;
|
||||||
|
|
||||||
|
if (active.lastCheckedLocation != null && active.lastCheckedLocation.getWorld().equals(currentLocation.getWorld()) && currentLocation.distanceSquared(active.lastCheckedLocation) > 0.001) {
|
||||||
|
active.lastMoveTimestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
active.lastCheckedLocation = currentLocation;
|
||||||
|
} else {
|
||||||
|
active = new ActiveTrim(currentMaterial, currentLocation);
|
||||||
|
if (activePlayers.containsKey(uuid)) {
|
||||||
|
animations.get(activePlayers.get(uuid).material).onRemove(player);
|
||||||
|
}
|
||||||
|
activePlayers.put(uuid, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialAnimation animation = animations.get(currentMaterial);
|
||||||
|
if (animation != null) {
|
||||||
|
long loopTime = active.ticks % animation.getLoopDuration();
|
||||||
|
long timeSinceLastMove = System.currentTimeMillis() - active.lastMoveTimestamp;
|
||||||
|
|
||||||
|
if (timeSinceLastMove < 1000) {
|
||||||
|
animation.onRemove(player);
|
||||||
|
animation.tickMoving(player, getViewers(player), loopTime);
|
||||||
|
} else {
|
||||||
|
animation.tickStationary(player, getViewers(player), loopTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startTicking() {
|
||||||
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), () -> Bukkit.getOnlinePlayers().forEach(this::tickPlayer),0,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValidMaterial getActiveMaterial(Player player) {
|
||||||
|
ItemStack[] armor = player.getInventory().getArmorContents();
|
||||||
|
if (armor.length != 4) return null;
|
||||||
|
|
||||||
|
ValidMaterial found = null;
|
||||||
|
for (ItemStack piece : armor) {
|
||||||
|
if (!ArmorUtils.isArmor(piece)) return null;
|
||||||
|
|
||||||
|
ItemMeta meta = piece.getItemMeta();
|
||||||
|
if (!(meta instanceof ArmorMeta armorMeta)) return null;
|
||||||
|
if (!armorMeta.hasTrim()) return null;
|
||||||
|
|
||||||
|
ArmorTrim trim = armorMeta.getTrim();
|
||||||
|
if (trim == null) return null;
|
||||||
|
|
||||||
|
ValidMaterial vm = ValidMaterial.validate(trim.getMaterial());
|
||||||
|
if (vm == null) return null;
|
||||||
|
|
||||||
|
if (found == null) {
|
||||||
|
found = vm;
|
||||||
|
} else if (found != vm) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldHide(Player player) {
|
||||||
|
return getStorage().disabledOwnParticles.contains(player.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Player> getViewers(Player player) {
|
||||||
|
if (shouldHide(player)) return new HashSet<>();
|
||||||
|
return Bukkit.getOnlinePlayers().stream().filter(viewer-> !getStorage().disabledGlobalParticles.contains(viewer.getUniqueId().toString())).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ActiveTrim {
|
||||||
|
final ValidMaterial material;
|
||||||
|
long ticks;
|
||||||
|
long lastMoveTimestamp;
|
||||||
|
Location lastCheckedLocation;
|
||||||
|
|
||||||
|
ActiveTrim(ValidMaterial material, Location initialLocation) {
|
||||||
|
this.material = material;
|
||||||
|
this.ticks = 0;
|
||||||
|
this.lastMoveTimestamp = System.currentTimeMillis();
|
||||||
|
this.lastCheckedLocation = initialLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public enum ValidArmorType {
|
||||||
|
LEATHER(Material.LEATHER_HELMET,Material.LEATHER_CHESTPLATE,Material.LEATHER_LEGGINGS,Material.LEATHER_BOOTS),
|
||||||
|
GOLDEN(Material.GOLDEN_HELMET,Material.GOLDEN_CHESTPLATE,Material.GOLDEN_LEGGINGS,Material.GOLDEN_BOOTS),
|
||||||
|
CHAINMAIL(Material.CHAINMAIL_HELMET,Material.CHAINMAIL_CHESTPLATE,Material.CHAINMAIL_LEGGINGS,Material.CHAINMAIL_BOOTS),
|
||||||
|
IRON(Material.IRON_HELMET,Material.IRON_CHESTPLATE,Material.IRON_LEGGINGS,Material.IRON_BOOTS),
|
||||||
|
DIAMOND(Material.DIAMOND_HELMET,Material.DIAMOND_CHESTPLATE,Material.DIAMOND_LEGGINGS,Material.DIAMOND_BOOTS),
|
||||||
|
NETHERITE(Material.NETHERITE_HELMET,Material.NETHERITE_CHESTPLATE,Material.NETHERITE_LEGGINGS,Material.NETHERITE_BOOTS);
|
||||||
|
|
||||||
|
private final Material helmet;
|
||||||
|
private final Material chestplate;
|
||||||
|
private final Material leggings;
|
||||||
|
private final Material boots;
|
||||||
|
|
||||||
|
ValidArmorType(Material helmet, Material chestplate, Material leggings, Material boots) {
|
||||||
|
this.helmet = helmet;
|
||||||
|
this.chestplate = chestplate;
|
||||||
|
this.leggings = leggings;
|
||||||
|
this.boots = boots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getHelmet() {
|
||||||
|
return helmet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getChestplate() {
|
||||||
|
return chestplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getLeggings() {
|
||||||
|
return leggings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getBoots() {
|
||||||
|
return boots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidArmorType validate(Material armor) {
|
||||||
|
for (ValidArmorType value : values()) {
|
||||||
|
if (value.helmet.equals(armor) || value.chestplate.equals(armor) || value.leggings.equals(armor) || value.boots.equals(armor)) return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||||
|
|
||||||
|
public enum ValidMaterial {
|
||||||
|
AMETHYST(TrimMaterial.AMETHYST),
|
||||||
|
COPPER(TrimMaterial.COPPER),
|
||||||
|
DIAMOND(TrimMaterial.DIAMOND),
|
||||||
|
EMERALD(TrimMaterial.EMERALD),
|
||||||
|
GOLD(TrimMaterial.GOLD),
|
||||||
|
IRON(TrimMaterial.IRON),
|
||||||
|
LAPIS(TrimMaterial.LAPIS),
|
||||||
|
NETHERITE(TrimMaterial.NETHERITE),
|
||||||
|
QUARTZ(TrimMaterial.QUARTZ),
|
||||||
|
REDSTONE(TrimMaterial.REDSTONE);
|
||||||
|
|
||||||
|
private final TrimMaterial canonical;
|
||||||
|
|
||||||
|
ValidMaterial(TrimMaterial canonical) {
|
||||||
|
this.canonical = canonical;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrimMaterial getCanonical() {
|
||||||
|
return canonical;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidMaterial validate(TrimMaterial material) {
|
||||||
|
for (ValidMaterial value : ValidMaterial.values()) {
|
||||||
|
if (!value.getCanonical().equals(material)) continue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrimMaterial validate(String name) {
|
||||||
|
name = name.toUpperCase();
|
||||||
|
return ValidMaterial.valueOf(name).getCanonical();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AmethystAnimation extends MaterialAnimation {
|
||||||
|
private static final Color AMETHYST_COLOR = Color.fromRGB(139, 69, 190);
|
||||||
|
private static final long LOOP_DURATION = 120L;
|
||||||
|
|
||||||
|
public AmethystAnimation() {
|
||||||
|
super(ValidMaterial.AMETHYST, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.AMETHYST_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation().add(0, 0, 0);
|
||||||
|
|
||||||
|
double phase = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
double radius = 1.5 + 0.5 * Math.sin(phase * 2);
|
||||||
|
|
||||||
|
DisplayUtils.ring(playerLoc, radius, (point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(AMETHYST_COLOR,1F))
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loopTime % 5 == 0) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
Location particleLoc = playerLoc.clone().add(
|
||||||
|
Math.random() * 2 - 1,
|
||||||
|
Math.random() * 2,
|
||||||
|
Math.random() * 2 - 1
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ENCHANT)
|
||||||
|
.spawn(particleLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 20 == 0) {
|
||||||
|
DisplayUtils.helix(playerLoc.clone().subtract(0, 0.5, 0), 0.8, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(AMETHYST_COLOR,0.5F))
|
||||||
|
.spawn(loc);
|
||||||
|
}, 0.2, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class CopperAnimation extends MaterialAnimation {
|
||||||
|
|
||||||
|
private static final long LOOP_DURATION = 100L;
|
||||||
|
private final Map<UUID, List<BlockDisplay>> activeDisplays = new HashMap<>();
|
||||||
|
|
||||||
|
public CopperAnimation() {
|
||||||
|
super(ValidMaterial.COPPER, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.COPPER_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double angle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> {
|
||||||
|
List<BlockDisplay> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location loc = player.getLocation().add(0, 1, 0);
|
||||||
|
BlockDisplay display = player.getWorld().spawn(loc, BlockDisplay.class,disp->{
|
||||||
|
disp.setVisibleByDefault(false);
|
||||||
|
viewers.forEach(viewer->{
|
||||||
|
viewer.showEntity(main.getPlugin(),disp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
display.setBlock(Material.COPPER_BLOCK.createBlockData());
|
||||||
|
display.addScoreboardTag(main.getCommon().getTempTag());
|
||||||
|
display.setInterpolationDuration(1);
|
||||||
|
display.setInterpolationDelay(0);
|
||||||
|
list.add(display);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < displays.size(); i++) {
|
||||||
|
BlockDisplay display = displays.get(i);
|
||||||
|
|
||||||
|
double offsetAngle = angle + (i * Math.PI / 2);
|
||||||
|
double x = Math.cos(offsetAngle) * 2.0;
|
||||||
|
double z = Math.sin(offsetAngle) * 2.0;
|
||||||
|
double y = Math.sin(angle * 2) * 0.5;
|
||||||
|
|
||||||
|
Location blockLoc = playerLoc.clone().add(x, y + 1, z);
|
||||||
|
display.teleport(blockLoc);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.ELECTRIC_SPARK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(blockLoc);
|
||||||
|
|
||||||
|
float scale = 0.3f + 0.1f * (float) Math.sin(angle * 3);
|
||||||
|
Transformation transform = new Transformation(
|
||||||
|
new Vector3f(0, 0, 0),
|
||||||
|
new AxisAngle4f((float) angle, 0, 1, 0),
|
||||||
|
new Vector3f(scale, scale, scale),
|
||||||
|
new AxisAngle4f(0, 0, 0, 1)
|
||||||
|
);
|
||||||
|
display.setTransformation(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 25 == 0) {
|
||||||
|
Location groundLoc = player.getLocation();
|
||||||
|
DisplayUtils.wave(groundLoc, 4.0, 1.2f, 0.5, (point) -> {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.COPPER_BLOCK.createBlockData())
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 15 == 0) {
|
||||||
|
Location groundLoc = player.getLocation();
|
||||||
|
DisplayUtils.wave(groundLoc, 2.0, 0.4f, 0.2, (point) -> {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.WAX_ON)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {
|
||||||
|
List<BlockDisplay> displays = activeDisplays.remove(player.getUniqueId());
|
||||||
|
if (displays != null) {
|
||||||
|
for (BlockDisplay display : displays) {
|
||||||
|
if (!display.isDead()) {
|
||||||
|
display.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class DiamondAnimation extends MaterialAnimation {
|
||||||
|
private static final Color DIAMOND_COLOR = Color.fromRGB(185, 242, 255);
|
||||||
|
private static final long LOOP_DURATION = 160L;
|
||||||
|
|
||||||
|
private final Map<UUID, List<BlockDisplay>> activeDisplays = new HashMap<>();
|
||||||
|
|
||||||
|
public DiamondAnimation() {
|
||||||
|
super(ValidMaterial.DIAMOND, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.DIAMOND_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
Location playerLoc = player.getLocation().add(0, 1.5, 0);
|
||||||
|
double mainAngle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> {
|
||||||
|
List<BlockDisplay> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
Location initialLoc = player.getLocation().add(0, 1, 0);
|
||||||
|
BlockDisplay display = player.getWorld().spawn(initialLoc, BlockDisplay.class,disp->{
|
||||||
|
disp.setVisibleByDefault(false);
|
||||||
|
viewers.forEach(viewer->{
|
||||||
|
viewer.showEntity(main.getPlugin(),disp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
display.setBlock(Material.DIAMOND_BLOCK.createBlockData());
|
||||||
|
display.addScoreboardTag(main.getCommon().getTempTag());
|
||||||
|
display.setInterpolationDuration(1);
|
||||||
|
display.setInterpolationDelay(0);
|
||||||
|
list.add(display);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int orbit = 0; orbit < displays.size(); orbit++) {
|
||||||
|
BlockDisplay display = displays.get(orbit);
|
||||||
|
|
||||||
|
double orbitAngle = mainAngle * (1 + orbit * 0.3) + orbit * Math.PI * 2 / 3;
|
||||||
|
double radius = 1.8 - orbit * 0.2;
|
||||||
|
double height = Math.sin(orbitAngle * 2) * 0.8;
|
||||||
|
|
||||||
|
double x = Math.cos(orbitAngle) * radius;
|
||||||
|
double z = Math.sin(orbitAngle) * radius;
|
||||||
|
|
||||||
|
Location diamondLoc = playerLoc.clone().add(x, height, z);
|
||||||
|
display.teleport(diamondLoc);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(DIAMOND_COLOR,2F))
|
||||||
|
.speed(0.1F)
|
||||||
|
.spawn(diamondLoc);
|
||||||
|
|
||||||
|
float rotationAngle = (float)(orbitAngle * 2);
|
||||||
|
float scale = 0.25f + 0.05f * (float)Math.sin(mainAngle * 4);
|
||||||
|
|
||||||
|
Transformation transform = new Transformation(
|
||||||
|
new Vector3f(0, 0, 0),
|
||||||
|
new AxisAngle4f(rotationAngle, 1, 1, 1),
|
||||||
|
new Vector3f(scale, scale, scale),
|
||||||
|
new AxisAngle4f(0, 0, 0, 1)
|
||||||
|
);
|
||||||
|
display.setTransformation(transform);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 3 == 0) {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Location sparkLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 4,
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
(Math.random() - 0.5) * 4
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ELECTRIC_SPARK)
|
||||||
|
.speed(0.1F)
|
||||||
|
.spawn(sparkLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {
|
||||||
|
List<BlockDisplay> displays = activeDisplays.remove(player.getUniqueId());
|
||||||
|
if (displays != null) {
|
||||||
|
for (BlockDisplay display : displays) {
|
||||||
|
if (!display.isDead()) {
|
||||||
|
display.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class EmeraldAnimation extends MaterialAnimation {
|
||||||
|
private static final Color EMERALD_COLOR = Color.fromRGB(80, 220, 92);
|
||||||
|
private static final long LOOP_DURATION = 140L;
|
||||||
|
|
||||||
|
public EmeraldAnimation() {
|
||||||
|
super(ValidMaterial.EMERALD, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.EMERALD_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double time = loopTime / (double) LOOP_DURATION;
|
||||||
|
double spiralAngle = time * 4 * Math.PI;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
double heightOffset = (i / 6.0) * 3 - 1.5;
|
||||||
|
double radius = 1.2 + 0.3 * Math.sin(spiralAngle + i);
|
||||||
|
double angle = spiralAngle + i * Math.PI / 3;
|
||||||
|
|
||||||
|
double x = Math.cos(angle) * radius;
|
||||||
|
double z = Math.sin(angle) * radius;
|
||||||
|
|
||||||
|
Location spiralLoc = playerLoc.clone().add(x, heightOffset + 1, z);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(EMERALD_COLOR,0.5F))
|
||||||
|
.spawn(spiralLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
double pulsePhase = (loopTime % 30) / 30.0 * 2 * Math.PI;
|
||||||
|
double pulseRadius = 2.0 + 0.5 * Math.sin(pulsePhase);
|
||||||
|
DisplayUtils.ring(playerLoc, pulseRadius,0.9,(loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.HAPPY_VILLAGER)
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loopTime % 8 == 0) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
Location natureLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
Math.random() * 2,
|
||||||
|
(Math.random() - 0.5) * 3
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.COMPOSTER)
|
||||||
|
.spawn(natureLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GoldAnimation extends MaterialAnimation {
|
||||||
|
private static final Color GOLD_COLOR = Color.fromRGB(255, 215, 0);
|
||||||
|
private static final long LOOP_DURATION = 80L;
|
||||||
|
|
||||||
|
public GoldAnimation() {
|
||||||
|
super(ValidMaterial.GOLD, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
DisplayUtils.ring(player.getLocation().clone().add(0, 2.1, 0), 0.3, 0.5f,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(GOLD_COLOR,0.3F))
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.GOLD_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double crownAngle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
DisplayUtils.ring(player.getLocation().clone().add(0, 2.1, 0), 0.3, 0.5f,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(GOLD_COLOR,0.5F))
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loopTime % 4 == 0) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location fallLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 4,
|
||||||
|
Math.random() * 3 + 2,
|
||||||
|
(Math.random() - 0.5) * 4
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.GOLD_BLOCK.createBlockData())
|
||||||
|
.offset(0.2,0.2,0.2)
|
||||||
|
.speed(0.01F)
|
||||||
|
.spawn(fallLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double wealthPhase = (loopTime % 60) / 60.0 * 2 * Math.PI;
|
||||||
|
for (int ring = 0; ring < 3; ring++) {
|
||||||
|
double ringRadius = 0.5 + ring * 0.5;
|
||||||
|
double ringPhase = wealthPhase + ring * Math.PI / 2;
|
||||||
|
double ringHeight = Math.sin(ringPhase) * 0.3;
|
||||||
|
|
||||||
|
DisplayUtils.ring(playerLoc.clone().add(0, ringHeight + 0.6, 0), ringRadius, 0.8f,(loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(GOLD_COLOR,0.5F))
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 6 == 0) {
|
||||||
|
Location sparkleLoc = playerLoc.clone().add(
|
||||||
|
Math.cos(crownAngle * 3) * 2,
|
||||||
|
Math.sin(crownAngle * 2) * 1.5,
|
||||||
|
Math.sin(crownAngle * 3) * 2
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ELECTRIC_SPARK)
|
||||||
|
.offset(0.2,0.2,0.2)
|
||||||
|
.speed(0.3F)
|
||||||
|
.spawn(sparkleLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.ItemDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class IronAnimation extends MaterialAnimation {
|
||||||
|
private static final Color IRON_COLOR = Color.fromRGB(145, 145, 145);
|
||||||
|
private static final long LOOP_DURATION = 60L;
|
||||||
|
private static final List<Material> IRON_ITEMS = List.of(
|
||||||
|
Material.IRON_AXE,
|
||||||
|
Material.IRON_SWORD,
|
||||||
|
Material.IRON_PICKAXE,
|
||||||
|
Material.IRON_SHOVEL,
|
||||||
|
Material.IRON_HOE,
|
||||||
|
Material.IRON_INGOT
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Map<UUID, List<ItemDisplay>> activeDisplays = new HashMap<>();
|
||||||
|
|
||||||
|
public IronAnimation() {
|
||||||
|
super(ValidMaterial.IRON, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.IRON_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double shieldAngle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
List<ItemDisplay> items = activeDisplays.computeIfAbsent(playerId, id -> {
|
||||||
|
List<ItemDisplay> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location initialLoc = player.getLocation().add(0, 1, 0);
|
||||||
|
ItemDisplay shield = player.getWorld().spawn(initialLoc, ItemDisplay.class,disp->{
|
||||||
|
disp.setVisibleByDefault(false);
|
||||||
|
viewers.forEach(viewer->{
|
||||||
|
viewer.showEntity(main.getPlugin(),disp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
shield.setItemStack(new ItemStack(main.randomizer().getRandomElement(IRON_ITEMS)));
|
||||||
|
shield.addScoreboardTag(main.getCommon().getTempTag());
|
||||||
|
shield.setInterpolationDuration(1);
|
||||||
|
shield.setInterpolationDelay(0);
|
||||||
|
list.add(shield);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
ItemDisplay item = items.get(i);
|
||||||
|
|
||||||
|
double angle = shieldAngle + (i * Math.PI / 2);
|
||||||
|
double distance = 2.2 + 0.3 * Math.sin(shieldAngle * 3);
|
||||||
|
|
||||||
|
double x = Math.cos(angle) * distance;
|
||||||
|
double z = Math.sin(angle) * distance;
|
||||||
|
double y = 1.0 + Math.sin(shieldAngle * 2 + i) * 0.3;
|
||||||
|
|
||||||
|
Location shieldLoc = playerLoc.clone().add(x, y, z);
|
||||||
|
item.teleport(shieldLoc);
|
||||||
|
|
||||||
|
float rotY = (float) angle;
|
||||||
|
float scale = 0.8f;
|
||||||
|
|
||||||
|
Transformation transform = new Transformation(
|
||||||
|
new Vector3f(0, 0, 0),
|
||||||
|
new AxisAngle4f(rotY, 0, 1, 0),
|
||||||
|
new Vector3f(scale, scale, scale),
|
||||||
|
new AxisAngle4f(0, 0, 0, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
item.setTransformation(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 10 == 0) {
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
Location firworkLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
Math.random() * 2.5,
|
||||||
|
(Math.random() - 0.5) * 3
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.FIREWORK)
|
||||||
|
.speed(0.1F)
|
||||||
|
.spawn(firworkLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 30 == 0) {
|
||||||
|
DisplayUtils.wave(playerLoc, 3.5, loc->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(IRON_COLOR,1F))
|
||||||
|
.spawn(loc);
|
||||||
|
}, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 5 == 0) {
|
||||||
|
Location dustLoc = playerLoc.clone().add(0, 0.1, 0);
|
||||||
|
DisplayUtils.ring(dustLoc, 1.8, 0.18,(loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.IRON_BLOCK)
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {
|
||||||
|
List<ItemDisplay> displays = activeDisplays.remove(player.getUniqueId());
|
||||||
|
if (displays != null) {
|
||||||
|
for (ItemDisplay display : displays) {
|
||||||
|
if (!display.isDead()) {
|
||||||
|
display.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class LapisAnimation extends MaterialAnimation {
|
||||||
|
private static final Color LAPIS_COLOR = Color.fromRGB(31, 64, 181);
|
||||||
|
private static final long LOOP_DURATION = 120L;
|
||||||
|
|
||||||
|
public LapisAnimation() {
|
||||||
|
super(ValidMaterial.LAPIS, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
DisplayUtils.ring(player.getLocation().clone().add(0, 2.1, 0), 0.3, 0.5f,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.ENCHANT)
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.LAPIS_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().clone().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double magicAngle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
DisplayUtils.ring(player.getLocation().clone().add(0, 2.1, 0), 0.3, 0.5f,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.ENCHANT)
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int circle = 0; circle < 3; circle++) {
|
||||||
|
double circleHeight = circle * 0.8 - 0.8;
|
||||||
|
double circleAngle = magicAngle * (1 + circle * 0.5);
|
||||||
|
double circleRadius = 1.5 - circle * 0.2;
|
||||||
|
|
||||||
|
Location circleCenter = playerLoc.clone().add(0, circleHeight, 0);
|
||||||
|
|
||||||
|
for (int segment = 0; segment < 6; segment++) {
|
||||||
|
int startAngle = (int)(Math.toDegrees(circleAngle) + segment * 60);
|
||||||
|
int endAngle = startAngle + 30;
|
||||||
|
|
||||||
|
DisplayUtils.arc(circleCenter, circleRadius, startAngle, endAngle, 0.2, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(LAPIS_COLOR,0.5F))
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 8 == 0) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
double runeAngle = magicAngle + i * Math.PI / 2;
|
||||||
|
Location runeLoc = playerLoc.clone().add(
|
||||||
|
Math.cos(runeAngle) * 2.5,
|
||||||
|
Math.sin(magicAngle * 2) * 0.5 + 1,
|
||||||
|
Math.sin(runeAngle) * 2.5
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ENCHANT)
|
||||||
|
.count(3)
|
||||||
|
.offset(0.1,0.1,0.1)
|
||||||
|
.spawn(runeLoc);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ENCHANTED_HIT)
|
||||||
|
.count(3)
|
||||||
|
.offset(0.1,0.1,0.1)
|
||||||
|
.spawn(runeLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 15 == 0) {
|
||||||
|
DisplayUtils.vortex(playerLoc.clone().subtract(0, 0.5, 0), 0.8,(loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(LAPIS_COLOR,0.5F))
|
||||||
|
.spawn(loc);
|
||||||
|
},
|
||||||
|
0.05, 0.25, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 12 == 0) {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Location sparkLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
Math.random() * 2,
|
||||||
|
(Math.random() - 0.5) * 3
|
||||||
|
);
|
||||||
|
sparkLoc.getWorld().spawnParticle(Particle.ELECTRIC_SPARK, sparkLoc, 1, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double pulsePhase = (loopTime % 40) / 40.0 * 2 * Math.PI;
|
||||||
|
double pulseIntensity = 0.5 + 0.5 * Math.sin(pulsePhase);
|
||||||
|
Color pulseLapis = Color.fromRGB(
|
||||||
|
(int)(31 * pulseIntensity + 100 * (1 - pulseIntensity)),
|
||||||
|
(int)(64 * pulseIntensity + 150 * (1 - pulseIntensity)),
|
||||||
|
(int)(181 * pulseIntensity + 255 * (1 - pulseIntensity))
|
||||||
|
);
|
||||||
|
|
||||||
|
DisplayUtils.ring(playerLoc, 2.2, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(pulseLapis,0.5F))
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class NetheriteAnimation extends MaterialAnimation {
|
||||||
|
private static final Color NETHERITE_COLOR = Color.fromRGB(68, 58, 59);
|
||||||
|
private static final long LOOP_DURATION = 200L;
|
||||||
|
|
||||||
|
private final Map<UUID, List<BlockDisplay>> activeDisplays = new HashMap<>();
|
||||||
|
|
||||||
|
public NetheriteAnimation() {
|
||||||
|
super(ValidMaterial.NETHERITE, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.LAVA)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().clone().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double angle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
|
||||||
|
List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> {
|
||||||
|
List<BlockDisplay> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location initialLoc = player.getLocation().add(0, 1, 0);
|
||||||
|
BlockDisplay display = player.getWorld().spawn(initialLoc, BlockDisplay.class,disp->{
|
||||||
|
disp.setVisibleByDefault(false);
|
||||||
|
viewers.forEach(viewer->{
|
||||||
|
viewer.showEntity(main.getPlugin(),disp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
display.setBlock(Material.NETHERITE_BLOCK.createBlockData());
|
||||||
|
display.addScoreboardTag(main.getCommon().getTempTag());
|
||||||
|
display.setInterpolationDuration(1);
|
||||||
|
display.setInterpolationDelay(0);
|
||||||
|
list.add(display);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < displays.size(); i++) {
|
||||||
|
BlockDisplay display = displays.get(i);
|
||||||
|
|
||||||
|
double offsetAngle = angle + (i * Math.PI / 2);
|
||||||
|
double x = Math.cos(offsetAngle) * 2.0;
|
||||||
|
double z = Math.sin(offsetAngle) * 2.0;
|
||||||
|
double y = Math.sin(angle * 2) * 0.5;
|
||||||
|
|
||||||
|
Location blockLoc = playerLoc.clone().add(x, y + 1, z);
|
||||||
|
display.teleport(blockLoc);
|
||||||
|
|
||||||
|
float scale = 0.5f + 0.1f * (float) Math.sin(angle * 3);
|
||||||
|
Transformation transform = new Transformation(
|
||||||
|
new Vector3f(0, 0, 0),
|
||||||
|
new AxisAngle4f((float) angle, 0, 1, 0),
|
||||||
|
new Vector3f(scale, scale, scale),
|
||||||
|
new AxisAngle4f(0, 0, 0, 1)
|
||||||
|
);
|
||||||
|
display.setTransformation(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 6 == 0) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Location fireLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 6,
|
||||||
|
Math.random() * 0.5,
|
||||||
|
(Math.random() - 0.5) * 6
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.SOUL_FIRE_FLAME)
|
||||||
|
.spawn(fireLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 50 == 0) {
|
||||||
|
DisplayUtils.fanWaveRandom(playerLoc, 4.5, 8, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(NETHERITE_COLOR,0.8F))
|
||||||
|
.spawn(loc);
|
||||||
|
}, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
double auraPhase = (loopTime % 60) / 60.0 * 2 * Math.PI;
|
||||||
|
double auraRadius = 2.8 + 0.7 * Math.sin(auraPhase * 2);
|
||||||
|
DisplayUtils.ring(playerLoc.clone().add(0, 0.2, 0), auraRadius,0.8, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.FLAME)
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loopTime % 10 == 0) {
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
Location emberLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 5,
|
||||||
|
Math.random() * 3 + 1,
|
||||||
|
(Math.random() - 0.5) * 5
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.LAVA)
|
||||||
|
.spawn(emberLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {
|
||||||
|
List<BlockDisplay> displays = activeDisplays.remove(player.getUniqueId());
|
||||||
|
if (displays != null) {
|
||||||
|
for (BlockDisplay display : displays) {
|
||||||
|
if (!display.isDead()) {
|
||||||
|
display.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.TaskManager;
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class QuartzAnimation extends MaterialAnimation {
|
||||||
|
private static final Color QUARTZ_COLOR = Color.fromRGB(255, 252, 245);
|
||||||
|
private static final long LOOP_DURATION = 100L;
|
||||||
|
|
||||||
|
public QuartzAnimation() {
|
||||||
|
super(ValidMaterial.QUARTZ, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.QUARTZ_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().clone().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double angle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
double offsetAngle = angle + (i * Math.PI / 2);
|
||||||
|
double x = Math.cos(offsetAngle) * 2.0;
|
||||||
|
double z = Math.sin(offsetAngle) * 2.0;
|
||||||
|
double y = Math.sin(angle * 2) * 0.5;
|
||||||
|
|
||||||
|
Location particleOrbit = playerLoc.clone().add(x, y + 1, z);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.QUARTZ_BLOCK)
|
||||||
|
.count(1)
|
||||||
|
.speed(0)
|
||||||
|
.spawn(particleOrbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 4 == 0) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location sparkleLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 4,
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
(Math.random() - 0.5) * 4
|
||||||
|
);
|
||||||
|
sparkleLoc.getWorld().spawnParticle(Particle.END_ROD, sparkleLoc, 1, 0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double purifyPhase = (loopTime % 50) / 50.0 * 2 * Math.PI;
|
||||||
|
for (int ring = 0; ring < 2; ring++) {
|
||||||
|
double ringRadius = 1.8 + ring * 0.8;
|
||||||
|
double ringPhase = purifyPhase + ring * Math.PI;
|
||||||
|
double ringHeight = Math.sin(ringPhase) * 0.4;
|
||||||
|
|
||||||
|
DisplayUtils.ring(playerLoc.clone().add(0, ringHeight, 0), ringRadius,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(QUARTZ_COLOR,1F))
|
||||||
|
.viewers(viewers)
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trims.animations;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.server.systems.visual.ParticleUtils;
|
||||||
|
import me.trouper.clonedupecore.server.trims.MaterialAnimation;
|
||||||
|
import me.trouper.clonedupecore.server.trims.ValidMaterial;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RedstoneAnimation extends MaterialAnimation {
|
||||||
|
private static final Color REDSTONE_COLOR = Color.fromRGB(255, 0, 0);
|
||||||
|
private static final Color REDSTONE_DIM = Color.fromRGB(120, 0, 0);
|
||||||
|
private static final long LOOP_DURATION = 80L; // 4 seconds
|
||||||
|
|
||||||
|
public RedstoneAnimation() {
|
||||||
|
super(ValidMaterial.REDSTONE, LOOP_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickMoving(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.type(Particle.BLOCK)
|
||||||
|
.data(Material.REDSTONE_BLOCK)
|
||||||
|
.viewers(viewers)
|
||||||
|
.offset(0.3,0.3,0.3)
|
||||||
|
.count(5)
|
||||||
|
.speed(0.05F)
|
||||||
|
.spawn(player.getLocation().clone().add(0,0.1,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickStationary(Player player, Set<Player> viewers, long loopTime) {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double circuitPhase = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
|
||||||
|
boolean isPowered = Math.sin(circuitPhase * 4) > 0;
|
||||||
|
Color currentColor = isPowered ? REDSTONE_COLOR : REDSTONE_DIM;
|
||||||
|
|
||||||
|
double pathAngle = circuitPhase * 0.5;
|
||||||
|
for (int path = 0; path < 8; path++) {
|
||||||
|
double lineAngle = pathAngle + path * Math.PI / 4;
|
||||||
|
double startRadius = 0.8;
|
||||||
|
double endRadius = 2.5;
|
||||||
|
|
||||||
|
for (double r = startRadius; r <= endRadius; r += 0.2) {
|
||||||
|
double x = Math.cos(lineAngle) * r;
|
||||||
|
double z = Math.sin(lineAngle) * r;
|
||||||
|
Location lineLoc = playerLoc.clone().add(x, 0, z);
|
||||||
|
|
||||||
|
boolean sectionPowered = isPowered && ((int)(r * 5) % 3 != 0);
|
||||||
|
Color sectionColor = sectionPowered ? REDSTONE_COLOR : REDSTONE_DIM;
|
||||||
|
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(sectionColor,0.5F))
|
||||||
|
.spawn(lineLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPowered && loopTime % 8 == 0) {
|
||||||
|
for (int torch = 0; torch < 4; torch++) {
|
||||||
|
double torchAngle = circuitPhase + torch * Math.PI / 2;
|
||||||
|
Location torchLoc = playerLoc.clone().add(
|
||||||
|
Math.cos(torchAngle) * 2.2,
|
||||||
|
0.5,
|
||||||
|
Math.sin(torchAngle) * 2.2
|
||||||
|
);
|
||||||
|
|
||||||
|
DisplayUtils.beam(torchLoc,
|
||||||
|
(loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.PORTAL)
|
||||||
|
.spawn(loc);
|
||||||
|
},
|
||||||
|
0.1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 30 == 0) {
|
||||||
|
DisplayUtils.wave(playerLoc.clone(), 3.0, 0.8f, 0.4, (loc)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.ENCHANTED_HIT)
|
||||||
|
.spawn(loc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopTime % 6 == 0) {
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
Location dustLoc = playerLoc.clone().add(
|
||||||
|
(Math.random() - 0.5) * 3,
|
||||||
|
(Math.random() - 0.5) * 2,
|
||||||
|
(Math.random() - 0.5) * 3
|
||||||
|
);
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(currentColor,0.5F))
|
||||||
|
.spawn(dustLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double coreIntensity = isPowered ? 1.0 : 0.3;
|
||||||
|
Color coreColor = Color.fromRGB(
|
||||||
|
(int)(255 * coreIntensity),
|
||||||
|
(int)(50 * coreIntensity),
|
||||||
|
(int)(50 * coreIntensity)
|
||||||
|
);
|
||||||
|
|
||||||
|
DisplayUtils.ring(playerLoc, 1.2, 0.2f,(point)->{
|
||||||
|
ParticleUtils.builder()
|
||||||
|
.viewers(viewers)
|
||||||
|
.type(Particle.DUST)
|
||||||
|
.data(new Particle.DustOptions(coreColor,0.5F))
|
||||||
|
.spawn(point);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(Player player) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.User;
|
||||||
|
import com.github.retrooper.packetevents.protocol.world.Difficulty;
|
||||||
|
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionTypes;
|
||||||
|
import com.github.retrooper.packetevents.util.Vector3d;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCamera;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateHealth;
|
||||||
|
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||||
|
import me.trouper.clonedupecore.utils.PacketUtils;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CameraTroll implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "camera";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.SAFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Sets the player's camera to a random mob.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {
|
||||||
|
User user = PacketUtils.getUser(target);
|
||||||
|
int entityID = target.getWorld().getEntityCount()+1;
|
||||||
|
WrapperPlayServerSpawnEntity spawnEntity = new WrapperPlayServerSpawnEntity(
|
||||||
|
entityID, UUID.randomUUID(), EntityTypes.ENDERMAN, SpigotConversionUtil.fromBukkitLocation(target.getLocation()),0,0,new Vector3d()
|
||||||
|
);
|
||||||
|
WrapperPlayServerCamera camera = new WrapperPlayServerCamera(entityID);
|
||||||
|
Difficulty diff = Difficulty.valueOf(target.getWorld().getDifficulty().toString());
|
||||||
|
GameMode gm = GameMode.valueOf(target.getGameMode().toString());
|
||||||
|
WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(
|
||||||
|
DimensionTypes.THE_END,
|
||||||
|
target.getWorld().getName(),
|
||||||
|
diff,
|
||||||
|
1L,
|
||||||
|
gm,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
WrapperPlayServerUpdateHealth health = new WrapperPlayServerUpdateHealth(Float.parseFloat("" + target.getHealth()),target.getFoodLevel(),target.getSaturation());
|
||||||
|
|
||||||
|
user.sendPacket(spawnEntity);
|
||||||
|
user.sendPacket(camera);
|
||||||
|
user.sendPacket(health);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.AbstractWand;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.server.systems.tracing.BlockDisplayRaytracer;
|
||||||
|
import me.trouper.alias.server.systems.tracing.CustomDisplayRaytracer;
|
||||||
|
import me.trouper.alias.server.systems.tracing.Point;
|
||||||
|
import me.trouper.alias.server.systems.visual.DisplayUtils;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import me.trouper.clonedupecore.utils.PlayerUtils;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.damage.DamageSource;
|
||||||
|
import org.bukkit.damage.DamageType;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class DragTrollWand extends AbstractWand implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "drag";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.DAMAGING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Gets a wand which you can use to controll players";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ItemStack DRAG_WAND = ItemBuilder.of(Material.BREEZE_ROD)
|
||||||
|
.displayName(Component.text("Drag Wand", NamedTextColor.DARK_AQUA).decoration(TextDecoration.ITALIC,false).decoration(TextDecoration.BOLD,true))
|
||||||
|
.loreComponent(
|
||||||
|
Text.color("&1▪ &bRight-Click:&7 Select Player"),
|
||||||
|
Text.color("&1▪ &bLeft-Click:&7 Throw"),
|
||||||
|
Text.color("&1▪ &bSneak Left-Click:&7 Electrocute")
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public DragTrollWand() {
|
||||||
|
super("clonedupe.troll", DRAG_WAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
private final Map<UUID, DragTask> playerDragMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRightClick(Player player) {
|
||||||
|
handleDragPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClick(Player player) {
|
||||||
|
handleThrowPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClickSneak(Player player) {
|
||||||
|
handleElectrocute(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollUp(Player p) {
|
||||||
|
if (!playerDragMap.containsKey(p.getUniqueId())) return;
|
||||||
|
DragTask task = playerDragMap.get(p.getUniqueId());
|
||||||
|
|
||||||
|
task.setDistance(task.getDistance() + 0.5);
|
||||||
|
SoundPlayer.play(p,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 0.8F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollDown(Player p) {
|
||||||
|
if (!playerDragMap.containsKey(p.getUniqueId())) return;
|
||||||
|
DragTask task = playerDragMap.get(p.getUniqueId());
|
||||||
|
|
||||||
|
if (task.getDistance() < 1.5) {
|
||||||
|
task.setDistance(2D);
|
||||||
|
SoundPlayer.play(p,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.3F);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task.setDistance(task.getDistance() - 0.5);
|
||||||
|
SoundPlayer.play(p,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDragPlayer(Player user) {
|
||||||
|
if (playerDragMap.containsKey(user.getUniqueId())) {
|
||||||
|
DragTask task = playerDragMap.remove(user.getUniqueId());
|
||||||
|
Entity target = task.drop();
|
||||||
|
if (target == null) return;
|
||||||
|
|
||||||
|
success(user,Component.text("You are no longer holding {0}."),target.name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomDisplayRaytracer.trace(user.getEyeLocation(),user.getEyeLocation().getDirection(),30,0.5, point -> {
|
||||||
|
List<Entity> targets = point.getNearbyEntities(user,1, entity -> entity instanceof LivingEntity);
|
||||||
|
if (targets.isEmpty()) return false;
|
||||||
|
LivingEntity target = (LivingEntity) targets.getFirst();
|
||||||
|
|
||||||
|
playerDragMap.put(user.getUniqueId(),startDragging(user,target));
|
||||||
|
target.setGlowing(true);
|
||||||
|
if (target instanceof Player t) t.setAllowFlight(true);
|
||||||
|
|
||||||
|
DisplayUtils.helix(target.getLocation(),0.6,(helix)->{
|
||||||
|
user.getWorld().spawnParticle(Particle.SOUL_FIRE_FLAME,helix,1,0,0,0,0);
|
||||||
|
},0.02,2);
|
||||||
|
|
||||||
|
success(user,Component.text("You are now holding {0}."),target.name());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private DragTask startDragging(Player user, LivingEntity victim) {
|
||||||
|
return new DragTask(victim.getUniqueId(), Bukkit.getScheduler().runTaskTimer(main.getPlugin(), () -> {
|
||||||
|
if (victim == null) {
|
||||||
|
playerDragMap.remove(user.getUniqueId()).drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (victim instanceof Player v && !v.isOnline()) {
|
||||||
|
playerDragMap.remove(user.getUniqueId()).drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DragTask task = playerDragMap.get(user.getUniqueId());
|
||||||
|
|
||||||
|
Point point = CustomDisplayRaytracer.blocksInFrontOf(user.getEyeLocation(), user.getEyeLocation().getDirection(),task.getDistance(), false);
|
||||||
|
victim.teleport(point.getLoc().clone().subtract(0, 1, 0));
|
||||||
|
|
||||||
|
user.sendActionBar(Component.text("You ", NamedTextColor.GREEN).append(Component.text("⇄ ",NamedTextColor.WHITE)).append(Component.text(victim.getName(),NamedTextColor.AQUA)).append(Component.text(" | ",NamedTextColor.GRAY)).append(Component.text(Math.round(task.getDistance()),NamedTextColor.DARK_GREEN)));
|
||||||
|
}, 0, 1),user.getLocation().distance(victim.getLocation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleThrowPlayer(Player user) {
|
||||||
|
if (!playerDragMap.containsKey(user.getUniqueId())) return;
|
||||||
|
|
||||||
|
DragTask task = playerDragMap.remove(user.getUniqueId());
|
||||||
|
Entity target = task.launch(user);
|
||||||
|
if (target == null) return;
|
||||||
|
|
||||||
|
success(user,Component.text("You have thrown {0}."),target.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleElectrocute(Player user) {
|
||||||
|
if (!playerDragMap.containsKey(user.getUniqueId())) return;
|
||||||
|
|
||||||
|
DragTask task = playerDragMap.get(user.getUniqueId());
|
||||||
|
Entity target = Bukkit.getEntity(task.dragged);
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
task.drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicInteger ticksRemaining = new AtomicInteger(60);
|
||||||
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(shockTask)->{
|
||||||
|
if (ticksRemaining.getAndDecrement() <= 0 || target == null) {
|
||||||
|
shockTask.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlayerUtils.instantTrueDamage((LivingEntity) target, DamageSource.builder(DamageType.INDIRECT_MAGIC).build(),0.1);
|
||||||
|
drawLightning(user.getLocation().clone().add(0,1,0),target.getLocation(),Material.AMETHYST_BLOCK,Material.PURPLE_STAINED_GLASS);
|
||||||
|
},0,1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawLightning(Location start, Location end, Material blockInner, Material blockOuter) {
|
||||||
|
int segments = 10;
|
||||||
|
double maxOffset = 0.5;
|
||||||
|
long stayTime = 10L;
|
||||||
|
double thickness = 0.02;
|
||||||
|
double thicknessOut = 0.04;
|
||||||
|
List<Player> viewers = new ArrayList<>(start.getWorld().getPlayers());
|
||||||
|
|
||||||
|
Location current = start.clone();
|
||||||
|
Vector direction = end.clone().subtract(start).toVector();
|
||||||
|
double segmentLength = direction.length() / segments;
|
||||||
|
direction.normalize().multiply(segmentLength);
|
||||||
|
|
||||||
|
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
for (int i = 0; i < segments; i++) {
|
||||||
|
Vector offset = new Vector(
|
||||||
|
(localRandom.nextDouble() - 0.5) * maxOffset,
|
||||||
|
(localRandom.nextDouble() - 0.5) * maxOffset,
|
||||||
|
(localRandom.nextDouble() - 0.5) * maxOffset
|
||||||
|
);
|
||||||
|
Location next = current.clone().add(direction).add(offset);
|
||||||
|
|
||||||
|
BlockDisplayRaytracer.trace(blockInner, current, next, thickness, stayTime, viewers);
|
||||||
|
BlockDisplayRaytracer.trace(blockOuter, current, next, thicknessOut, stayTime, viewers);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDisplayRaytracer.trace(blockInner, current, end, thickness, stayTime, viewers);
|
||||||
|
BlockDisplayRaytracer.trace(blockOuter, current, end, thicknessOut, stayTime, viewers);
|
||||||
|
end.getWorld().spawnParticle(Particle.FLASH,end,0,0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DragTask {
|
||||||
|
private final UUID dragged;
|
||||||
|
private final BukkitTask task;
|
||||||
|
private double distance;
|
||||||
|
|
||||||
|
private DragTask(UUID dragged, BukkitTask task, double distance) {
|
||||||
|
this.dragged = dragged;
|
||||||
|
this.task = task;
|
||||||
|
if (Double.isNaN(distance)) distance = 5;
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getDragged() {
|
||||||
|
return dragged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitTask getTask() {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistance(double distance) {
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entity drop() {
|
||||||
|
this.getTask().cancel();
|
||||||
|
Entity target = Bukkit.getEntity(this.getDragged());
|
||||||
|
if (target == null) return null;
|
||||||
|
|
||||||
|
target.setGlowing(false);
|
||||||
|
if (target instanceof Player t) t.setAllowFlight(false);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entity launch(Player thrower) {
|
||||||
|
Entity target = this.drop();
|
||||||
|
if (target == null) return null;
|
||||||
|
|
||||||
|
target.setVelocity(target.getVelocity().add(thrower.getEyeLocation().getDirection().normalize().multiply(2)));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class FlickerTroll implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "flicker";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Makes the target's screen flicker with the wake up animation.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.SAFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<UUID> eepyPlayers = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {
|
||||||
|
var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
|
||||||
|
eepyPlayers.add(target.getUniqueId());
|
||||||
|
Bukkit.getScheduler().runTaskTimerAsynchronously(main.getPlugin(), (t) -> {
|
||||||
|
if (!eepyPlayers.contains(target.getUniqueId())) t.cancel();
|
||||||
|
player.sendPacket(new WrapperPlayServerEntityAnimation(target.getEntityId(), WrapperPlayServerEntityAnimation.EntityAnimationType.WAKE_UP));
|
||||||
|
}, 1, 1);
|
||||||
|
successAny(sender,"{0}'s screen is now flickering",target.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {
|
||||||
|
if (eepyPlayers.remove(target.getUniqueId())) successAny(sender,"Stopped flickering {0}'s screen.",target.getName());
|
||||||
|
else errorAny(sender,"{0}'s screen is not flickering.",target.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.User;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import me.trouper.clonedupecore.utils.PacketUtils;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class LSDTroll implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "lsd";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Makes the player hallucinate.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.SAFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Material> RAINBOW_BLOCKS = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
Material.RED_WOOL,
|
||||||
|
Material.ORANGE_WOOL,
|
||||||
|
Material.YELLOW_WOOL,
|
||||||
|
Material.LIME_WOOL,
|
||||||
|
Material.LIGHT_BLUE_WOOL,
|
||||||
|
Material.MAGENTA_WOOL,
|
||||||
|
Material.PURPLE_WOOL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final List<Material> RAINBOW_GLASS = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
Material.RED_STAINED_GLASS,
|
||||||
|
Material.ORANGE_STAINED_GLASS,
|
||||||
|
Material.YELLOW_STAINED_GLASS,
|
||||||
|
Material.LIME_STAINED_GLASS,
|
||||||
|
Material.LIGHT_BLUE_STAINED_GLASS,
|
||||||
|
Material.MAGENTA_STAINED_GLASS,
|
||||||
|
Material.PURPLE_STAINED_GLASS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Map<UUID,BukkitTask> lsdTasks = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {
|
||||||
|
if (lsdTasks.containsKey(target.getUniqueId())) {
|
||||||
|
error(sender,Component.text("{0} is already hallucinating!"),target.name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
User v = PacketEvents.getAPI().getPlayerManager().getUser(target);
|
||||||
|
final int radius = 8;
|
||||||
|
AtomicInteger ticksPassed = new AtomicInteger(0);
|
||||||
|
|
||||||
|
lsdTasks.put(target.getUniqueId(),Bukkit.getScheduler().runTaskTimer(main.getPlugin(),()->{
|
||||||
|
if (!target.isOnline()) {
|
||||||
|
try {
|
||||||
|
lsdTasks.remove(target.getUniqueId()).cancel();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = target.getLocation().getBlockX();
|
||||||
|
int y = target.getLocation().getBlockY();
|
||||||
|
int z = target.getLocation().getBlockZ();
|
||||||
|
World w = target.getWorld();
|
||||||
|
|
||||||
|
Location center = target.getLocation();
|
||||||
|
for (int xLoc = x - radius; xLoc < x + radius; xLoc++) {
|
||||||
|
for (int yLoc = y - radius; yLoc < y + radius; yLoc++) {
|
||||||
|
for (int zLoc = z - radius; zLoc < z + radius; zLoc++) {
|
||||||
|
Location loc = new Location(w,xLoc,yLoc,zLoc);
|
||||||
|
if (loc.distanceSquared(center) >= radius*radius) continue;
|
||||||
|
Block block = loc.getBlock();
|
||||||
|
|
||||||
|
if (block.isPassable()) {
|
||||||
|
if (loc.distanceSquared(center) <= (radius-3)*(radius-3)) {
|
||||||
|
PacketUtils.sendGhostBlock(v,loc,block.getType());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double distance = loc.distance(center);
|
||||||
|
int waveIndex = (int) ((ticksPassed.get() / 2.0 - distance) % RAINBOW_GLASS.size());
|
||||||
|
if (waveIndex < 0) waveIndex += RAINBOW_GLASS.size();
|
||||||
|
Material waveMaterial = RAINBOW_GLASS.get(waveIndex);
|
||||||
|
|
||||||
|
PacketUtils.sendGhostBlock(v, loc, waveMaterial);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double distance = loc.distance(center);
|
||||||
|
int waveIndex = (int) ((ticksPassed.get() / 2.0 - distance) % RAINBOW_BLOCKS.size());
|
||||||
|
if (waveIndex < 0) waveIndex += RAINBOW_BLOCKS.size();
|
||||||
|
Material waveMaterial = RAINBOW_BLOCKS.get(waveIndex);
|
||||||
|
|
||||||
|
PacketUtils.sendGhostBlock(v, loc, waveMaterial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float pitch = ((float) (ticksPassed.get() % 5)) / 10;
|
||||||
|
|
||||||
|
SoundPlayer.play(target,Sound.BLOCK_NOTE_BLOCK_CHIME,10,pitch + 0.7F);
|
||||||
|
ticksPassed.incrementAndGet();
|
||||||
|
},0,2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {
|
||||||
|
try {
|
||||||
|
lsdTasks.remove(target.getUniqueId()).cancel();
|
||||||
|
success(sender, Component.text("Stopped {0}'s hallucinations."),target.name());
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
error(sender, Component.text("{0} is not hallucinating."),target.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.User;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPlayerInventory;
|
||||||
|
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import net.kyori.adventure.title.Title;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class LiarTroll implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "liar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Liar, liar, pants on trinitrotoluene!";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.DAMAGING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<UUID,ItemStack> activeLiars = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {
|
||||||
|
User t = PacketEvents.getAPI().getPlayerManager().getUser(target);
|
||||||
|
activeLiars.put(target.getUniqueId(),target.getEquipment().getLeggings());
|
||||||
|
|
||||||
|
AtomicBoolean inverse = new AtomicBoolean(false);
|
||||||
|
AtomicInteger timeRemaining = new AtomicInteger(30 * 20);
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task)->{
|
||||||
|
if (!activeLiars.containsKey(target.getUniqueId())) {
|
||||||
|
task.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeRemaining.get() <= 0) {
|
||||||
|
WrapperPlayServerSetPlayerInventory packet = new WrapperPlayServerSetPlayerInventory(37,SpigotConversionUtil.fromBukkitItemStack(activeLiars.get(target.getUniqueId())));
|
||||||
|
t.sendPacket(packet);
|
||||||
|
target.getWorld().createExplosion(target.getLocation(),1,false,false);
|
||||||
|
task.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack displayItem = ItemBuilder.of(Material.TNT)
|
||||||
|
.displayName(Component.text("Liar, Liar!", NamedTextColor.RED).decoration(TextDecoration.ITALIC,false).decorate(TextDecoration.BOLD))
|
||||||
|
.loreComponent(
|
||||||
|
Component.text("Pants on trinitrotoluene!",NamedTextColor.GRAY),
|
||||||
|
Component.text("Explodes in ", NamedTextColor.GRAY).append(Component.text(timeRemaining.get() / 20,NamedTextColor.DARK_RED)).append(Component.text(" seconds.",NamedTextColor.GRAY))
|
||||||
|
)
|
||||||
|
.enchant(Enchantment.BINDING_CURSE)
|
||||||
|
.flags(ItemFlag.HIDE_ENCHANTS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
WrapperPlayServerSetPlayerInventory packet = new WrapperPlayServerSetPlayerInventory(37,SpigotConversionUtil.fromBukkitItemStack(displayItem));
|
||||||
|
Title title = Title.title(
|
||||||
|
Text.color("&c⚠ &4&lWARNING &r&c⚠"),
|
||||||
|
Text.color("&7&nLEGGINGS COMBUSTION EMINENT!"),
|
||||||
|
Title.Times.times(Duration.of(0, ChronoUnit.SECONDS),Duration.of(1, ChronoUnit.SECONDS),Duration.of(0, ChronoUnit.SECONDS))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inverse.get()) {
|
||||||
|
title = Title.title(
|
||||||
|
Text.color("&e⚠ &4&l&nWARNING&r &e⚠"),
|
||||||
|
Text.color("&7LEGGINGS COMBUSTION EMINENT!"),
|
||||||
|
Title.Times.times(Duration.of(0, ChronoUnit.SECONDS),Duration.of(1, ChronoUnit.SECONDS),Duration.of(0, ChronoUnit.SECONDS)))
|
||||||
|
;
|
||||||
|
ItemStack pants = displayItem.withType(Material.WHITE_WOOL);
|
||||||
|
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, SoundCategory.MASTER,10,2F);
|
||||||
|
packet.setStack(SpigotConversionUtil.fromBukkitItemStack(pants));
|
||||||
|
} else {
|
||||||
|
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, SoundCategory.MASTER,10,1.5F);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.sendPacket(packet);
|
||||||
|
target.showTitle(title);
|
||||||
|
target.getWorld().spawnParticle(Particle.SMOKE,target.getLocation().add(0,0.5,0),1,0.1,0.1,0.1,0.05);
|
||||||
|
|
||||||
|
if (timeRemaining.get() <= 40) target.setFireTicks(2);
|
||||||
|
if (timeRemaining.getAndSet(timeRemaining.get() - 1) % 10 == 0) inverse.set(!inverse.get());
|
||||||
|
},0,1);
|
||||||
|
|
||||||
|
successAny(sender,"{0} will soon detonate!",target.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {
|
||||||
|
if (activeLiars.remove(target.getUniqueId()) != null) successAny(sender,"Removed the TNT from {0}'s pants.",target.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChangeGameState;
|
||||||
|
import me.trouper.clonedupecore.utils.PlayerUtils;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.damage.DamageSource;
|
||||||
|
import org.bukkit.damage.DamageType;
|
||||||
|
import org.bukkit.entity.Display;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.TextDisplay;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class MatrixTroll implements TrollFeature {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "matrix";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Make the player escape The Matrix.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.HARMLESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<UUID, MatrixSession> matrixUsers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {
|
||||||
|
if (matrixUsers.containsKey(target.getUniqueId())) {
|
||||||
|
error(sender,Component.text("{0} is already escaping The Matrix."),target.name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatrixSession session = new MatrixSession(target);
|
||||||
|
matrixUsers.put(target.getUniqueId(), session);
|
||||||
|
session.start();
|
||||||
|
success(sender,Component.text("Making {0} run from The Matrix."),target.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {
|
||||||
|
MatrixSession session = matrixUsers.remove(target.getUniqueId());
|
||||||
|
if (session != null) {
|
||||||
|
session.stop();
|
||||||
|
success(sender,Component.text("Removed {0}'s Matirx."),target.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Component generateMatrix(int width, int height) {
|
||||||
|
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
|
||||||
|
Component matrix = Component.empty();
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
Component line = Component.empty();
|
||||||
|
if (y > 0) {
|
||||||
|
line = line.appendNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
char bit = (char) ('\u30A0' + localRandom.nextInt(96));
|
||||||
|
|
||||||
|
int greenValue = 100 + localRandom.nextInt(156);
|
||||||
|
TextColor green = TextColor.color(0, greenValue, 0);
|
||||||
|
|
||||||
|
TextColor finalColor = localRandom.nextDouble() < 0.05 ? TextColor.color(200, 255, 200) : green;
|
||||||
|
|
||||||
|
Component charComp = Component.text(bit).color(finalColor);
|
||||||
|
line = line.append(charComp);
|
||||||
|
}
|
||||||
|
matrix = matrix.append(line);
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MatrixSession {
|
||||||
|
private final Player player;
|
||||||
|
private final List<MatrixColumn> columns = new ArrayList<>();
|
||||||
|
private BukkitTask spawnTask;
|
||||||
|
private BukkitTask updateTask;
|
||||||
|
private BukkitTask collisionTask;
|
||||||
|
private boolean active = true;
|
||||||
|
private int spawnRadius = 5;
|
||||||
|
private int maxColumns = 10;
|
||||||
|
|
||||||
|
public MatrixSession(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
spawnTask = Bukkit.getScheduler().runTaskTimer(getPlugin(), () -> {
|
||||||
|
if (!active || !player.isOnline()) {
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnSingleColumn();
|
||||||
|
}, 0L, 2L);
|
||||||
|
|
||||||
|
updateTask = Bukkit.getScheduler().runTaskTimer(getPlugin(), () -> {
|
||||||
|
if (!active) return;
|
||||||
|
|
||||||
|
for (MatrixColumn column : columns) {
|
||||||
|
column.updateDisplays();
|
||||||
|
}
|
||||||
|
}, 0L, 2L);
|
||||||
|
|
||||||
|
collisionTask = Bukkit.getScheduler().runTaskTimer(getPlugin(), () -> {
|
||||||
|
if (!active || !player.isOnline()) {
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollisionsAndLevitation();
|
||||||
|
}, 0L, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
active = false;
|
||||||
|
|
||||||
|
if (spawnTask != null) spawnTask.cancel();
|
||||||
|
if (updateTask != null) updateTask.cancel();
|
||||||
|
if (collisionTask != null) collisionTask.cancel();
|
||||||
|
|
||||||
|
for (MatrixColumn column : columns) {
|
||||||
|
column.remove();
|
||||||
|
}
|
||||||
|
columns.clear();
|
||||||
|
|
||||||
|
player.removePotionEffect(PotionEffectType.LEVITATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnSingleColumn() {
|
||||||
|
if (columns.size() >= maxColumns) {
|
||||||
|
columns.getFirst().remove();
|
||||||
|
columns.removeFirst();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
|
||||||
|
double angle = localRandom.nextDouble() * 2 * Math.PI;
|
||||||
|
double distance = localRandom.nextDouble() * spawnRadius;
|
||||||
|
|
||||||
|
double x = playerLoc.getX() + Math.cos(angle) * distance;
|
||||||
|
double z = playerLoc.getZ() + Math.sin(angle) * distance;
|
||||||
|
double y = playerLoc.getY() - 20;
|
||||||
|
|
||||||
|
Location columnLoc = new Location(playerLoc.getWorld(), x, y, z);
|
||||||
|
MatrixColumn column = new MatrixColumn(columnLoc);
|
||||||
|
columns.add(column);
|
||||||
|
column.spawn();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCollisionsAndLevitation() {
|
||||||
|
Location playerLoc = player.getLocation();
|
||||||
|
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
|
||||||
|
boolean inColumn = false;
|
||||||
|
MatrixColumn touchedColumn = null;
|
||||||
|
|
||||||
|
for (MatrixColumn column : columns) {
|
||||||
|
if (column.getBoundingBox().contains(playerLoc.toVector())) {
|
||||||
|
inColumn = true;
|
||||||
|
touchedColumn = column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inColumn) {
|
||||||
|
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10, 0, false, false));
|
||||||
|
|
||||||
|
|
||||||
|
if (localRandom.nextDouble() < 0.5) PlayerUtils.instantTrueDamage(player, DamageSource.builder(DamageType.HOT_FLOOR).build(),0.01);
|
||||||
|
if (localRandom.nextDouble() < 0.01) PacketEvents.getAPI().getPlayerManager().getUser(player).sendPacket(new WrapperPlayServerChangeGameState(WrapperPlayServerChangeGameState.Reason.PLAY_ELDER_GUARDIAN_MOB_APPEARANCE,0.0F));
|
||||||
|
|
||||||
|
List<MatrixColumn> toRemove = new ArrayList<>();
|
||||||
|
for (MatrixColumn column : columns) {
|
||||||
|
if (column != touchedColumn) {
|
||||||
|
column.remove();
|
||||||
|
toRemove.add(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columns.removeAll(toRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MatrixColumn {
|
||||||
|
private final Location center;
|
||||||
|
private final List<TextDisplay> displays = new ArrayList<>();
|
||||||
|
private final BoundingBox boundingBox;
|
||||||
|
private final int height = 40;
|
||||||
|
|
||||||
|
public MatrixColumn(Location center) {
|
||||||
|
this.center = center.clone();
|
||||||
|
|
||||||
|
this.boundingBox = new BoundingBox(
|
||||||
|
center.getX() - 0.5, center.getY(), center.getZ() - 0.5,
|
||||||
|
center.getX() + 0.5, center.getY() + height, center.getZ() + 0.5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn() {
|
||||||
|
float[] yaws = {0f, 90f, 180f, 270f};
|
||||||
|
double offset = 0.5;
|
||||||
|
Vector[] directions = {
|
||||||
|
new Vector(0, 0, -offset),
|
||||||
|
new Vector(offset, 0, 0),
|
||||||
|
new Vector(0, 0, offset),
|
||||||
|
new Vector(-offset, 0, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
float textScale = 2.5f;
|
||||||
|
final Transformation scaleTransform = new Transformation(
|
||||||
|
new Vector3f(),
|
||||||
|
new Quaternionf(),
|
||||||
|
new Vector3f(textScale, textScale, textScale),
|
||||||
|
new Quaternionf()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Location displayLoc = center.clone().add(directions[i]);
|
||||||
|
displayLoc.add(0, height/4, 0);
|
||||||
|
displayLoc.setYaw(yaws[i]);
|
||||||
|
Component text = generateMatrix(2, height);
|
||||||
|
|
||||||
|
int finalI = i;
|
||||||
|
|
||||||
|
TextDisplay displayOut = center.getWorld().spawn(displayLoc, TextDisplay.class, CreatureSpawnEvent.SpawnReason.CUSTOM, entity -> {
|
||||||
|
entity.text(text);
|
||||||
|
entity.setBillboard(Display.Billboard.FIXED);
|
||||||
|
entity.setVisibleByDefault(false);
|
||||||
|
entity.setRotation(yaws[finalI], 0f);
|
||||||
|
entity.setBackgroundColor(Color.fromARGB(0xDD000000));
|
||||||
|
entity.setTransformation(scaleTransform);
|
||||||
|
});
|
||||||
|
|
||||||
|
TextDisplay displayIn = center.getWorld().spawn(displayLoc, TextDisplay.class, CreatureSpawnEvent.SpawnReason.CUSTOM, entity -> {
|
||||||
|
entity.text(text);
|
||||||
|
entity.setBillboard(Display.Billboard.FIXED);
|
||||||
|
entity.setVisibleByDefault(false);
|
||||||
|
entity.setRotation(yaws[finalI] + 180f, 0f);
|
||||||
|
entity.setBackgroundColor(Color.fromARGB(0xDD000000));
|
||||||
|
entity.setTransformation(scaleTransform);
|
||||||
|
});
|
||||||
|
|
||||||
|
Player target = matrixUsers.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getValue().columns.stream().anyMatch(col -> col == this))
|
||||||
|
.map(entry -> Bukkit.getPlayer(entry.getKey()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (target != null) {
|
||||||
|
target.showEntity(getPlugin(), displayIn);
|
||||||
|
target.showEntity(getPlugin(), displayOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
displays.add(displayOut);
|
||||||
|
displays.add(displayIn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateDisplays() {
|
||||||
|
for (TextDisplay display : displays) {
|
||||||
|
if (!display.isDead()) {
|
||||||
|
display.text(generateMatrix(2, height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundingBox getBoundingBox() {
|
||||||
|
return boundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkCollision(Location playerLoc) {
|
||||||
|
for (TextDisplay display : displays) {
|
||||||
|
if (display.getLocation().distance(playerLoc) < 1.0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
for (TextDisplay display : displays) {
|
||||||
|
display.remove();
|
||||||
|
}
|
||||||
|
displays.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,514 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.AbstractWand;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.server.systems.Verbose;
|
||||||
|
import me.trouper.alias.server.systems.tracing.BlockDisplayRaytracer;
|
||||||
|
import me.trouper.alias.server.systems.tracing.CustomDisplayRaytracer;
|
||||||
|
import me.trouper.alias.server.systems.tracing.Point;
|
||||||
|
import me.trouper.alias.server.systems.world.ExplosionOptions;
|
||||||
|
import me.trouper.alias.server.systems.world.ExplosionResult;
|
||||||
|
import me.trouper.alias.server.systems.world.ExplosionUtils;
|
||||||
|
import me.trouper.alias.utils.FormatUtils;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class OrbitalTrollWand extends AbstractWand implements TrollFeature {
|
||||||
|
private static final ItemStack ORBITAL_WAND = ItemBuilder.of(Material.TRIPWIRE_HOOK)
|
||||||
|
.displayName(Text.color("&4&lOrbital Sky Torch").decoration(TextDecoration.ITALIC,false))
|
||||||
|
.loreComponent(
|
||||||
|
Text.color("&8▪ &cRight-Click:&f Aim Cannon"),
|
||||||
|
Text.color("&8▪ &cRight-Click Again:&f Charge Ion Beam"),
|
||||||
|
Text.color("&8▪ &cLeft-Click:&f Call off shot"),
|
||||||
|
Text.color("&8▪ &cSwap-Hands:&f Undo"),
|
||||||
|
Text.color("&7"),
|
||||||
|
Text.color("&7Now Includes &oreal&r&7 orbital configurations!"),
|
||||||
|
Text.color("&7"),
|
||||||
|
Text.color("&8Thank you TheCymaera and HeroBrayden!")
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public OrbitalTrollWand() {
|
||||||
|
super("clonedupe.orbital", ORBITAL_WAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "orbital";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Get a wand which lets you control the server's orbital ion cannon.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.DESTRUCTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {}
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
private final Map<UUID, OrbitalIonCannon> cannonMap = new HashMap<>();
|
||||||
|
private final Map<UUID, Stack<ExplosionResult>> playerHistory = new HashMap<>();
|
||||||
|
|
||||||
|
private boolean undoHistory(Player player) {
|
||||||
|
Stack<ExplosionResult> history = playerHistory.getOrDefault(player.getUniqueId(),new Stack<>());
|
||||||
|
if (history == null || history.isEmpty()) return false;
|
||||||
|
try (ExplosionResult result = history.pop()) {
|
||||||
|
result.restore();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSwapHand(Player player) {
|
||||||
|
try {
|
||||||
|
if (undoHistory(player)) {
|
||||||
|
Text.message(Text.Pallet.SUCCESS,false,player, Component.text("Restored previous explosion."));
|
||||||
|
} else {
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("Undo stack is empty!"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("An exception was thrown when undoing the explosion! Check console for details."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRightClick(Player player) {
|
||||||
|
if (cannonMap.containsKey(player.getUniqueId())) {
|
||||||
|
OrbitalIonCannon playerCannon = cannonMap.get(player.getUniqueId());
|
||||||
|
if (playerCannon.getFireTask() != null || playerCannon.getChargeTask() != null) {
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("You are already charging the Ion Cannon!"));
|
||||||
|
cannonMap.remove(player.getUniqueId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
playerCannon.charge();
|
||||||
|
cannonMap.remove(player.getUniqueId());
|
||||||
|
Text.message(Text.Pallet.SUCCESS,false,player, Component.text("Charging Ion Cannon..."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OrbitalIonCannon cannon = new OrbitalIonCannon(player, traceTargets(player));
|
||||||
|
cannonMap.put(player.getUniqueId(),cannon);
|
||||||
|
Text.message(Text.Pallet.SUCCESS,false,player, Component.text("You can now aim the Ion Cannon."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClick(Player player) {
|
||||||
|
if (!cannonMap.containsKey(player.getUniqueId())) {
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("You are not controlling the Ion Cannon."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OrbitalIonCannon playerCannon = cannonMap.get(player.getUniqueId());
|
||||||
|
playerCannon.destroy();
|
||||||
|
cannonMap.remove(player.getUniqueId());
|
||||||
|
Text.message(Text.Pallet.SUCCESS,false,player, Component.text("Deactivated Ion Cannon Safely."));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollDown(Player player) {
|
||||||
|
if (!cannonMap.containsKey(player.getUniqueId())) {
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("You are not controlling the Ion Cannon."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbitalIonCannon cannon = cannonMap.get(player.getUniqueId());
|
||||||
|
|
||||||
|
if (cannon.getPower() <= 1) {
|
||||||
|
SoundPlayer.play(player,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.3F);
|
||||||
|
cannon.setPower(2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cannon.setPower(Math.max(1,cannon.getPower() - 5));
|
||||||
|
SoundPlayer.play(player,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.7F);
|
||||||
|
|
||||||
|
player.sendActionBar(Text.format(Text.Pallet.INFO,"Set ion cannon power to {0}.",cannon.getPower()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollUp(Player player) {
|
||||||
|
if (!cannonMap.containsKey(player.getUniqueId())) {
|
||||||
|
Text.message(Text.Pallet.ERROR,false,player,Component.text("You are not controlling the Ion Cannon."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbitalIonCannon cannon = cannonMap.get(player.getUniqueId());
|
||||||
|
|
||||||
|
if (cannon.getPower() >= 50) {
|
||||||
|
SoundPlayer.play(player,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.3F);
|
||||||
|
cannon.setPower(49);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cannon.setPower(Math.min(50,cannon.getPower() + 5));
|
||||||
|
SoundPlayer.play(player,Sound.BLOCK_NOTE_BLOCK_HAT, 1, 0.8F);
|
||||||
|
|
||||||
|
player.sendActionBar(Text.format(Text.Pallet.INFO,"Set ion cannon power to {0}.",cannon.getPower()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OrbitalIonCannon {
|
||||||
|
private final Player owner;
|
||||||
|
private final OrbitalConfiguration simulatedOrbit;
|
||||||
|
private Location skyRenderLocation;
|
||||||
|
private Location skyTraceLocation;
|
||||||
|
private Location targetLocation;
|
||||||
|
private Location groundTraced;
|
||||||
|
private BukkitTask aimTask;
|
||||||
|
private BukkitTask chargeTask;
|
||||||
|
private BukkitTask fireTask;
|
||||||
|
private int power;
|
||||||
|
private ExplosionResult explosionResult;
|
||||||
|
private final BukkitTask tickTask = new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateOrbitLocation();
|
||||||
|
setSkyRenderLocation(getSimulatedOrbit().getRenderLocation(getTargetLocation()));
|
||||||
|
setSkyTraceLocation(CustomDisplayRaytracer.blocksInFrontOf(getTargetLocation(),getSimulatedOrbit().getNormalToSatellite(getTargetLocation().toVector()),20,false).getLoc());
|
||||||
|
if (!getAimTask().isCancelled()) {
|
||||||
|
setTargetLocation(traceTargets(getOwner()));
|
||||||
|
setGroundTraced(CustomDisplayRaytracer.trace(getSkyTraceLocation(),getTargetLocation(),5,(point)-> {
|
||||||
|
Material type = point.getLoc().getBlock().getType();
|
||||||
|
boolean collidable = type.isCollidable();
|
||||||
|
Verbose.send("Block at {0} collision: {1}, {2}",point.getLoc(),type,collidable);
|
||||||
|
return collidable;
|
||||||
|
}).getLoc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(main.getPlugin(), 0, 1);
|
||||||
|
|
||||||
|
private OrbitalIonCannon(Player owner, Location target) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.targetLocation = target;
|
||||||
|
this.power = 20;
|
||||||
|
this.simulatedOrbit = new OrbitalConfiguration(target.toVector());
|
||||||
|
|
||||||
|
this.setAimTask(aimRunnable.runTaskTimer(main.getPlugin(), 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final BukkitRunnable fireRunnable = new BukkitRunnable() {
|
||||||
|
int ticksElapsed = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ticksElapsed >= 120) {
|
||||||
|
if (getExplosionResult() != null) {
|
||||||
|
getExplosionResult().close();
|
||||||
|
}
|
||||||
|
destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed <= 40) {
|
||||||
|
BlockDisplay inner = BlockDisplayRaytracer.trace(Material.WHITE_CONCRETE_POWDER,getGroundTraced(),getSkyRenderLocation(),1,2);
|
||||||
|
inner.setGlowing(true);
|
||||||
|
inner.setGlowColorOverride(Color.fromRGB(0xFFDDDD));
|
||||||
|
BlockDisplayRaytracer.trace(Material.WHITE_STAINED_GLASS,getGroundTraced(),getSkyRenderLocation(),1.5 + main.random().nextDouble(),2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed == 0) {
|
||||||
|
ExplosionOptions options = new ExplosionOptions()
|
||||||
|
.setMaxBurnRadius(getPower())
|
||||||
|
.setFalloffRadius((double) getPower() / 3)
|
||||||
|
.setCoreRadius(((double) getPower() / 3) / 1.2)
|
||||||
|
.setBaseDamage(120)
|
||||||
|
.setBurnDelay(0)
|
||||||
|
.setDestructionDelay(1);
|
||||||
|
|
||||||
|
Stack<ExplosionResult> history = playerHistory.getOrDefault(getOwner().getUniqueId(),new Stack<>());
|
||||||
|
|
||||||
|
setExplosionResult(ExplosionUtils.createExplosion(getGroundTraced(),options));
|
||||||
|
|
||||||
|
history.push(getExplosionResult());
|
||||||
|
|
||||||
|
playerHistory.put(getOwner().getUniqueId(),history);
|
||||||
|
}
|
||||||
|
|
||||||
|
ticksElapsed++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final BukkitRunnable chargeRunnable = new BukkitRunnable() {
|
||||||
|
int ticksElapsed = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ticksElapsed >= 20) {
|
||||||
|
setFireTask(fireRunnable.runTaskTimer(main.getPlugin(),0,1));
|
||||||
|
this.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed == 1) {
|
||||||
|
new SoundPlayer(Sound.ENTITY_WARDEN_SONIC_CHARGE,30,0.5F).playAt(getTargetLocation(),40);
|
||||||
|
new SoundPlayer(Sound.BLOCK_CONDUIT_AMBIENT,30,0.5F).playAt(getGroundTraced(),40);
|
||||||
|
}
|
||||||
|
|
||||||
|
double thickness = (double) ticksElapsed / 20;
|
||||||
|
int otherValues = ((ticksElapsed / 20 * 100) + 100);
|
||||||
|
|
||||||
|
BlockDisplay inner = BlockDisplayRaytracer.trace(Material.RED_CONCRETE, getGroundTraced(),getSkyRenderLocation(),thickness,2);
|
||||||
|
inner.setGlowing(true);
|
||||||
|
inner.setGlowColorOverride(Color.fromRGB(255,otherValues,otherValues));
|
||||||
|
BlockDisplayRaytracer.trace(Material.ORANGE_STAINED_GLASS, getGroundTraced(),getSkyRenderLocation(),thickness + 0.1 ,2);
|
||||||
|
|
||||||
|
ticksElapsed++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final BukkitRunnable aimRunnable = new BukkitRunnable() {
|
||||||
|
int ticksElapsed = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (getChargeTask() != null) {
|
||||||
|
this.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksElapsed == 0) {
|
||||||
|
new SoundPlayer(Sound.BLOCK_RESPAWN_ANCHOR_CHARGE,1,0.5F).playAt(groundTraced,40);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDisplay inner = BlockDisplayRaytracer.trace(Material.RED_CONCRETE_POWDER,getGroundTraced(),getSkyRenderLocation(),0.1,2);
|
||||||
|
inner.setGlowing(true);
|
||||||
|
inner.setGlowColorOverride(Color.fromRGB(0xFF0000));
|
||||||
|
BlockDisplayRaytracer.trace(Material.RED_STAINED_GLASS,getGroundTraced(),getSkyRenderLocation(),0.2,2);
|
||||||
|
|
||||||
|
ticksElapsed++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void updateOrbitLocation() {
|
||||||
|
if (getTargetLocation() == null || getTargetLocation().getWorld() == null) {
|
||||||
|
destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSimulatedOrbit().tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroy() {
|
||||||
|
if (getTickTask() != null) this.getTickTask().cancel();
|
||||||
|
if (getFireTask() != null) this.getFireTask().cancel();
|
||||||
|
if (getChargeTask() != null) this.getChargeTask().cancel();
|
||||||
|
if (getAimTask() != null) this.getAimTask().cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void charge() {
|
||||||
|
this.getAimTask().cancel();
|
||||||
|
this.setChargeTask(this.chargeRunnable.runTaskTimer(main.getPlugin(),0,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getTargetLocation() {
|
||||||
|
return targetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetLocation(Location targetLocation) {
|
||||||
|
this.targetLocation = targetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitTask getAimTask() {
|
||||||
|
return aimTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAimTask(BukkitTask aimTask) {
|
||||||
|
this.aimTask = aimTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitTask getChargeTask() {
|
||||||
|
return chargeTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChargeTask(BukkitTask chargeTask) {
|
||||||
|
this.chargeTask = chargeTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitTask getFireTask() {
|
||||||
|
return fireTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFireTask(BukkitTask fireTask) {
|
||||||
|
this.fireTask = fireTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitTask getTickTask() {
|
||||||
|
return tickTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExplosionResult getExplosionResult() {
|
||||||
|
return explosionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExplosionResult(ExplosionResult explosionResult) {
|
||||||
|
this.explosionResult = explosionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrbitalConfiguration getSimulatedOrbit() {
|
||||||
|
return simulatedOrbit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getSkyRenderLocation() {
|
||||||
|
return skyRenderLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSkyRenderLocation(Location skyRenderLocation) {
|
||||||
|
this.skyRenderLocation = skyRenderLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getGroundTraced() {
|
||||||
|
return groundTraced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroundTraced(Location groundTraced) {
|
||||||
|
this.groundTraced = groundTraced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPower() {
|
||||||
|
return power;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPower(int power) {
|
||||||
|
this.power = power;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getSkyTraceLocation() {
|
||||||
|
return skyTraceLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSkyTraceLocation(Location skyTraceLocation) {
|
||||||
|
this.skyTraceLocation = skyTraceLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OrbitalConfiguration {
|
||||||
|
private Vector baseSatellite;
|
||||||
|
|
||||||
|
public OrbitalConfiguration(Vector center) {
|
||||||
|
this.baseSatellite = center.clone().setY(11_368_121);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
Vector orbitalLocation = getBaseSatellite();
|
||||||
|
if (orbitalLocation.getX() > 30_000_000 || orbitalLocation.getZ() > 30_000_000) {
|
||||||
|
setBaseSatellite(new Vector(-orbitalLocation.getX(),orbitalLocation.getY(),-orbitalLocation.getZ()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBaseSatellite(orbitalLocation.clone().add(new Vector(2_500,0,762)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getRenderLocation(Location center) {
|
||||||
|
Vector dir = getNormalToSatellite(center.toVector());
|
||||||
|
int castDistance = 128;
|
||||||
|
return center.clone().add(dir.getX() * castDistance, dir.getY() * castDistance, dir.getZ() * castDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNormalToSatellite(Vector target) {
|
||||||
|
Vector closestSatellite = getClosestSatellite(target).clone();
|
||||||
|
return closestSatellite.clone().subtract(target).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNormalToTarget(Vector target) {
|
||||||
|
Vector closestSatellite = getClosestSatellite(target).clone();
|
||||||
|
return target.clone().subtract(closestSatellite).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getClosestSatellite(Vector location) {
|
||||||
|
Vector[] satellites = new Vector[] {
|
||||||
|
getBaseSatellite(),
|
||||||
|
getPosXSat(),
|
||||||
|
getPosZSat(),
|
||||||
|
getPosXZSat(),
|
||||||
|
getNegXSat(),
|
||||||
|
getNegZSat(),
|
||||||
|
getNegXZSat(),
|
||||||
|
getPosXNegZSat(),
|
||||||
|
getNegXPosZSat()
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector closest = satellites[0];
|
||||||
|
double minDistance = location.distanceSquared(closest);
|
||||||
|
|
||||||
|
for (int i = 1; i < satellites.length; i++) {
|
||||||
|
double distance = location.distanceSquared(satellites[i]);
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
closest = satellites[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPosXSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(60_000_000,0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPosZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(0,0,60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPosXZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(60_000_000,0,60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNegXSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(-60_000_000,0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNegZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(0,0,-60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNegXZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(-60_000_000,0,60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPosXNegZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(60_000_000,0,-60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNegXPosZSat() {
|
||||||
|
return baseSatellite.clone().add(new Vector(-60_000_000,0,60_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getBaseSatellite() {
|
||||||
|
return baseSatellite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseSatellite(Vector baseSatellite) {
|
||||||
|
this.baseSatellite = baseSatellite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Location traceTargets(Player player) {
|
||||||
|
Point hit = CustomDisplayRaytracer.trace(player.getEyeLocation(),player.getEyeLocation().getDirection(),128,CustomDisplayRaytracer.HIT_BLOCK);
|
||||||
|
|
||||||
|
return hit.getLoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.AbstractWand;
|
||||||
|
import me.trouper.alias.server.systems.tracing.BlockDisplayRaytracer;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class TestTrollWand extends AbstractWand implements TrollFeature{
|
||||||
|
|
||||||
|
private static final ItemStack TEST_WAND = ItemBuilder.of(Material.TRIPWIRE_HOOK)
|
||||||
|
.displayName(Component.text("Testing Wand", NamedTextColor.YELLOW))
|
||||||
|
.loreComponent(
|
||||||
|
Component.text("Prints out the action you preformed.")
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "testwand";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "A wand for testing interfaces.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.SAFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestTrollWand() {
|
||||||
|
super("clonedupe.troll", TEST_WAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollUp(Player player) {
|
||||||
|
infoAny(player, "You scrolled upwards");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onScrollDown(Player player) {
|
||||||
|
infoAny(player, "You scrolled downwards");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSwapHand(Player player) {
|
||||||
|
infoAny(player, "You swapped hands");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSwapHandSneak(Player player) {
|
||||||
|
infoAny(player, "You swapped hands while sneaking");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClick(Player player) {
|
||||||
|
infoAny(player, "You left clicked");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClickSneak(Player player) {
|
||||||
|
infoAny(player, "You left clicked while sneaking");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRightClick(Player player) {
|
||||||
|
infoAny(player, "You right clicked");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRightClickSneak(Player player) {
|
||||||
|
infoAny(player, "You right clicked while sneaking");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.events.QuickListener;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public interface TrollFeature extends QuickListener {
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
Rating getRating();
|
||||||
|
|
||||||
|
void execute(CommandSender sender, Player target);
|
||||||
|
|
||||||
|
void stop(CommandSender sender, Player target);
|
||||||
|
|
||||||
|
enum Rating {
|
||||||
|
SAFE,
|
||||||
|
HARMLESS,
|
||||||
|
DAMAGING,
|
||||||
|
DESTRUCTIVE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
package me.trouper.clonedupecore.server.trolls;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.AbstractWand;
|
||||||
|
import me.trouper.alias.server.systems.Text;
|
||||||
|
import me.trouper.alias.server.systems.tracing.CustomDisplayRaytracer;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.alias.utils.SoundPlayer;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Display;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.joml.AxisAngle4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class VoidTrollWand extends AbstractWand implements TrollFeature {
|
||||||
|
private static final ItemStack VOID_WAND = ItemBuilder.of(Material.ECHO_SHARD)
|
||||||
|
.displayName(Text.color("&5&lVoid Wand").decoration(TextDecoration.ITALIC,false))
|
||||||
|
.loreComponent(
|
||||||
|
Text.color("&8▪ &dRight-Click:&f Abyss"),
|
||||||
|
Text.color("&8▪ &dLeft-Click:&f Engulf")
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Get a wand to harness the power of the void.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rating getRating() {
|
||||||
|
return Rating.DAMAGING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(CommandSender sender, Player target) {}
|
||||||
|
|
||||||
|
public VoidTrollWand() {
|
||||||
|
super("clonedupe.troll",VOID_WAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRightClick(Player player) {
|
||||||
|
CustomDisplayRaytracer.traceDelayed(main.getPlugin(),player.getEyeLocation(),player.getEyeLocation().getDirection(),30,1, point -> {
|
||||||
|
List<LivingEntity> targets = point.getNearbyEntities(player,1,true, entity->entity instanceof LivingEntity).stream().map(entity -> (LivingEntity) entity).toList();
|
||||||
|
if (targets.isEmpty()) {
|
||||||
|
SoundPlayer.play(point.getLoc(), Sound.BLOCK_SOUL_SAND_BREAK, 1,0.4F,10);
|
||||||
|
Particle.ASH.builder().location(point.getLoc()).offset(0.1,0.1,0.1).count(10).spawn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LivingEntity target = targets.getFirst();
|
||||||
|
|
||||||
|
Location targetLoc = target.getLocation().clone();
|
||||||
|
Location originalLoc = target.getLocation().clone().add(0,0.1,0);
|
||||||
|
SoundPlayer.play(target.getLocation(), Sound.ITEM_TRIDENT_THUNDER, 1,0.4F,10);
|
||||||
|
|
||||||
|
|
||||||
|
World w = target.getWorld();
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(task) -> {
|
||||||
|
if (counter.getAndIncrement() > 60) {
|
||||||
|
task.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.teleport(targetLoc.subtract(0, 0.05, 0));
|
||||||
|
w.spawnParticle(Particle.BLOCK, originalLoc, 50, 0.5, 0, 0.5, 0, Material.BLACK_CONCRETE.createBlockData());
|
||||||
|
w.spawnParticle(Particle.SQUID_INK, originalLoc, 50, 0.5, 0, 0.5, 0);
|
||||||
|
},0,1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLeftClick(Player player) {
|
||||||
|
CustomDisplayRaytracer.traceDelayed(main.getPlugin(),player.getEyeLocation(),player.getEyeLocation().getDirection(),30,1,point -> {
|
||||||
|
List<LivingEntity> targets = point.getNearbyEntities(player, 1, true, entity -> entity instanceof LivingEntity).stream().map(entity -> (LivingEntity) entity).toList();
|
||||||
|
if (targets.isEmpty()) {
|
||||||
|
SoundPlayer.play(point.getLoc(), Sound.BLOCK_SOUL_SAND_BREAK, 1,0.4F,10);
|
||||||
|
Particle.ASH.builder().location(point.getLoc()).offset(0.1, 0.1, 0.1).count(10).spawn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LivingEntity target = targets.getFirst();
|
||||||
|
|
||||||
|
engulf(target);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void engulf(LivingEntity target) {
|
||||||
|
List<BlockDisplay> displays = new ArrayList<>();
|
||||||
|
|
||||||
|
final double effectLength = 80;
|
||||||
|
final double maxHeight = 2.5;
|
||||||
|
final int blocksPerRing = 6;
|
||||||
|
final double ringSpacing = 0.3;
|
||||||
|
final double baseRadius = 0.8;
|
||||||
|
final double ticksPerRing = effectLength / (maxHeight / ringSpacing);
|
||||||
|
final Location targetLoc = target.getLocation();
|
||||||
|
|
||||||
|
AtomicInteger ticksElapsed = new AtomicInteger();
|
||||||
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(task)->{
|
||||||
|
if (ticksElapsed.getAndIncrement() > effectLength) {
|
||||||
|
target.setHealth(0);
|
||||||
|
SoundPlayer.play(targetLoc, Sound.ENTITY_DROWNED_DEATH_WATER, 1,0.4F,10);
|
||||||
|
displays.forEach(BlockDisplay::remove);
|
||||||
|
task.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double height = (ticksElapsed.get() / ticksPerRing) * ringSpacing;
|
||||||
|
displays.addAll(voidRing(targetLoc,height,baseRadius,blocksPerRing));
|
||||||
|
target.teleport(targetLoc);
|
||||||
|
SoundPlayer.play(targetLoc, Sound.BLOCK_BUBBLE_COLUMN_BUBBLE_POP, 1,0.4F,10);
|
||||||
|
if (ticksElapsed.get() % 20 == 0) SoundPlayer.play(targetLoc, Sound.ENTITY_DROWNED_HURT, 1,0.4F,10);
|
||||||
|
|
||||||
|
},0,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BlockDisplay> voidRing(Location center, double yOffset, double radius, int blockCount) {
|
||||||
|
List<BlockDisplay> displays = new ArrayList<>();
|
||||||
|
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
double angleStep = (2 * Math.PI) / blockCount;
|
||||||
|
|
||||||
|
for (int i = 0; i < blockCount; i++) {
|
||||||
|
double angle = i * angleStep;
|
||||||
|
|
||||||
|
double randomRadius = radius + (localRandom.nextDouble() - 0.5) * 0.5;
|
||||||
|
double x = center.getX() + Math.cos(angle) * randomRadius;
|
||||||
|
double z = center.getZ() + Math.sin(angle) * randomRadius;
|
||||||
|
double y = center.getY() + yOffset;
|
||||||
|
|
||||||
|
Location blockLoc = new Location(center.getWorld(), x, y, z);
|
||||||
|
|
||||||
|
BlockDisplay display = center.getWorld().spawn(blockLoc, BlockDisplay.class);
|
||||||
|
display.setBlock(Material.BLACK_CONCRETE.createBlockData());
|
||||||
|
display.addScoreboardTag("$/CloneDupeCore/ Temp");
|
||||||
|
display.setBrightness(new Display.Brightness(0,0));
|
||||||
|
|
||||||
|
Vector3f translation = new Vector3f(0, 0, 0);
|
||||||
|
Vector3f scale = new Vector3f(
|
||||||
|
0.6f + localRandom.nextFloat() * 0.8f,
|
||||||
|
0.6f + localRandom.nextFloat() * 0.8f,
|
||||||
|
0.6f + localRandom.nextFloat() * 0.8f
|
||||||
|
);
|
||||||
|
|
||||||
|
AxisAngle4f leftRotation = new AxisAngle4f(
|
||||||
|
localRandom.nextFloat() * (float)(2 * Math.PI),
|
||||||
|
localRandom.nextFloat() - 0.5f,
|
||||||
|
localRandom.nextFloat() - 0.5f,
|
||||||
|
localRandom.nextFloat() - 0.5f
|
||||||
|
);
|
||||||
|
AxisAngle4f rightRotation = new AxisAngle4f(0, 0, 0, 0);
|
||||||
|
|
||||||
|
Transformation transformation = new Transformation(translation, leftRotation, scale, rightRotation);
|
||||||
|
display.setTransformation(transformation);
|
||||||
|
|
||||||
|
displays.add(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return displays;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
44
src/main/java/me/trouper/clonedupecore/utils/ArmorUtils.java
Normal file
44
src/main/java/me/trouper/clonedupecore/utils/ArmorUtils.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package me.trouper.clonedupecore.utils;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class ArmorUtils {
|
||||||
|
public static boolean isArmor(ItemStack i) {
|
||||||
|
if (i == null || i.isEmpty()) return false;
|
||||||
|
|
||||||
|
return isHelmet(i) || isChestplate(i) || isLeggings(i) || isBoots(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHelmet(ItemStack i) {
|
||||||
|
if (i == null || i.isEmpty()) return false;
|
||||||
|
|
||||||
|
Material m = i.getType();
|
||||||
|
String n = m.name();
|
||||||
|
return n.contains("HELMET");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isChestplate(ItemStack i) {
|
||||||
|
if (i == null || i.isEmpty()) return false;
|
||||||
|
|
||||||
|
Material m = i.getType();
|
||||||
|
String n = m.name();
|
||||||
|
return n.contains("CHESTPLATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLeggings(ItemStack i) {
|
||||||
|
if (i == null || i.isEmpty()) return false;
|
||||||
|
|
||||||
|
Material m = i.getType();
|
||||||
|
String n = m.name();
|
||||||
|
return n.contains("LEGGINGS");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBoots(ItemStack i) {
|
||||||
|
if (i == null || i.isEmpty()) return false;
|
||||||
|
|
||||||
|
Material m = i.getType();
|
||||||
|
String n = m.name();
|
||||||
|
return n.contains("BOOTS");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package me.trouper.clonedupecore.utils;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.User;
|
||||||
|
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||||
|
import com.github.retrooper.packetevents.util.Vector3i;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
|
||||||
|
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PacketUtils {
|
||||||
|
public static void sendGhostBlock(User target, Location loc, Material material) {
|
||||||
|
if (!material.isBlock()) throw new IllegalArgumentException("Only block materials are allowed!");
|
||||||
|
Vector3i locVec = new Vector3i(loc.getBlockX(),loc.getBlockY(),loc.getBlockZ());
|
||||||
|
BlockData blockData = material.createBlockData();
|
||||||
|
WrappedBlockState data = SpigotConversionUtil.fromBukkitBlockData(blockData);
|
||||||
|
|
||||||
|
WrapperPlayServerBlockChange packet = new WrapperPlayServerBlockChange(locVec,data.getGlobalId());
|
||||||
|
packet.setBlockState(data);
|
||||||
|
target.sendPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User getUser(Player bukkitPlayer) {
|
||||||
|
return PacketEvents.getAPI().getPlayerManager().getUser(bukkitPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/main/java/me/trouper/clonedupecore/utils/PlayerUtils.java
Executable file
113
src/main/java/me/trouper/clonedupecore/utils/PlayerUtils.java
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
package me.trouper.clonedupecore.utils;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.damage.DamageSource;
|
||||||
|
import org.bukkit.entity.ArmorStand;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PlayerUtils {
|
||||||
|
|
||||||
|
private static float clampPitch(float pitch) {
|
||||||
|
return Math.max(-90, Math.min(90, pitch));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float wrapYaw(float yaw) {
|
||||||
|
yaw = yaw % 360;
|
||||||
|
if (yaw < 0) yaw += 360;
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector getDirection(float yaw, float pitch) {
|
||||||
|
double radYaw = Math.toRadians(yaw);
|
||||||
|
double radPitch = Math.toRadians(pitch);
|
||||||
|
double x = -Math.cos(radPitch) * Math.sin(radYaw);
|
||||||
|
double y = -Math.sin(radPitch);
|
||||||
|
double z = Math.cos(radPitch) * Math.cos(radYaw);
|
||||||
|
return new Vector(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Player playerClosestAngle(Player player, double range) {
|
||||||
|
Vector playerDirection = player.getEyeLocation().getDirection().normalize();
|
||||||
|
Location eyeLoc = player.getEyeLocation();
|
||||||
|
|
||||||
|
return player.getNearbyEntities(range, range, range).stream()
|
||||||
|
.filter(entity -> entity instanceof Player && !entity.equals(player))
|
||||||
|
.map(entity -> (Player) entity)
|
||||||
|
.min((p1, p2) -> {
|
||||||
|
Vector dirToP1 = p1.getEyeLocation().toVector().subtract(eyeLoc.toVector()).normalize();
|
||||||
|
Vector dirToP2 = p2.getEyeLocation().toVector().subtract(eyeLoc.toVector()).normalize();
|
||||||
|
|
||||||
|
double angle1 = playerDirection.angle(dirToP1);
|
||||||
|
double angle2 = playerDirection.angle(dirToP2);
|
||||||
|
|
||||||
|
return Double.compare(angle1, angle2);
|
||||||
|
})
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void instantDamage(LivingEntity target, DamageSource source, double amount) {
|
||||||
|
int max = target.getMaximumNoDamageTicks();
|
||||||
|
int ticks = target.getNoDamageTicks();
|
||||||
|
target.setMaximumNoDamageTicks(1);
|
||||||
|
target.setNoDamageTicks(0);
|
||||||
|
target.damage(amount,source);
|
||||||
|
target.setMaximumNoDamageTicks(max);
|
||||||
|
target.setNoDamageTicks(ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void instantTrueDamage(LivingEntity target, DamageSource source, double amount) {
|
||||||
|
int max = target.getMaximumNoDamageTicks();
|
||||||
|
int ticks = target.getNoDamageTicks();
|
||||||
|
target.setMaximumNoDamageTicks(1);
|
||||||
|
target.setNoDamageTicks(0);
|
||||||
|
dealTrueDamage(target,source,amount);
|
||||||
|
target.setMaximumNoDamageTicks(max);
|
||||||
|
target.setNoDamageTicks(ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dealTrueDamage(LivingEntity target, DamageSource source, double amount) {
|
||||||
|
if (source.getDirectEntity() instanceof Player a && target instanceof Player t) return;
|
||||||
|
|
||||||
|
EntityEquipment equipment = target.getEquipment();
|
||||||
|
if (equipment == null) {
|
||||||
|
target.damage(amount, source);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack helmet = equipment.getHelmet();
|
||||||
|
ItemStack chestplate = equipment.getChestplate();
|
||||||
|
ItemStack leggings = equipment.getLeggings();
|
||||||
|
ItemStack boots = equipment.getBoots();
|
||||||
|
|
||||||
|
equipment.setHelmet(null);
|
||||||
|
equipment.setChestplate(null);
|
||||||
|
equipment.setLeggings(null);
|
||||||
|
equipment.setBoots(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
target.damage(amount, source);
|
||||||
|
} finally {
|
||||||
|
equipment.setHelmet(helmet);
|
||||||
|
equipment.setChestplate(chestplate);
|
||||||
|
equipment.setLeggings(leggings);
|
||||||
|
equipment.setBoots(boots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
46
src/main/resources/plugin.yml
Normal file
46
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: CloneDupeCore
|
||||||
|
version: '1.0-SNAPSHOT'
|
||||||
|
main: me.trouper.clonedupecore.CloneDupeCore
|
||||||
|
api-version: '1.21'
|
||||||
|
depend:
|
||||||
|
- packetevents
|
||||||
|
- LiteBans
|
||||||
|
- NBTAPI
|
||||||
|
load: POSTWORLD
|
||||||
|
authors: [ obvWolf ]
|
||||||
|
description: Server Utilities for CloneDupe
|
||||||
|
commands:
|
||||||
|
ping:
|
||||||
|
usage: /ping [player]
|
||||||
|
permission: clonedupe.ping
|
||||||
|
description: Display the ping of you or another player.
|
||||||
|
clonetroll:
|
||||||
|
usage: /troll <feature> [player] [stop]
|
||||||
|
permission: clonedupe.troll
|
||||||
|
description: Many features to harras players with.
|
||||||
|
aliases:
|
||||||
|
- troll
|
||||||
|
- ct
|
||||||
|
clonedupecore:
|
||||||
|
usage: /clonedupecore <subcommand>
|
||||||
|
permission: clonedupe.admin
|
||||||
|
offend:
|
||||||
|
usage: "/offend <player> <query|punish> <offense>"
|
||||||
|
permission: clonedupe.offend
|
||||||
|
aliases:
|
||||||
|
- punish
|
||||||
|
trimeffect:
|
||||||
|
usage: /trimeffect <global|self>
|
||||||
|
permissions:
|
||||||
|
clonedupe.troll:
|
||||||
|
default: op
|
||||||
|
description: Allows a player to use troll features and the troll wand.
|
||||||
|
clonedupe.ping:
|
||||||
|
default: true
|
||||||
|
description: Allows the use of the ping command. Enabled by default.
|
||||||
|
clonedupe.admin:
|
||||||
|
default: op
|
||||||
|
description: Allows the use of the admin command.
|
||||||
|
clonedupe.offend:
|
||||||
|
default: op
|
||||||
|
description: Allows punishment of players through litebans.
|
||||||
Reference in New Issue
Block a user