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