first 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
|
||||||
55
build.gradle
Normal file
55
build.gradle
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'me.monster'
|
||||||
|
version = '1.0'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = "papermc-repo"
|
||||||
|
url = "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
// Configure the Minecraft version for our task.
|
||||||
|
// This is the only required configuration besides applying the plugin.
|
||||||
|
// Your plugin's jar (or shadowJar if present) will be used automatically.
|
||||||
|
minecraftVersion("1.21")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def targetJavaVersion = 21
|
||||||
|
java {
|
||||||
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
|
sourceCompatibility = javaVersion
|
||||||
|
targetCompatibility = javaVersion
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
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
Normal file
249
gradlew
vendored
Normal 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 = 'redmc-API'
|
||||||
18
src/main/java/me/monster/Main.java
Normal file
18
src/main/java/me/monster/Main.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package me.monster;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public final class Main extends JavaPlugin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
getLogger().info("Api Loaded");
|
||||||
|
// Plugin startup logic
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
// Plugin shutdown logic
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
56
src/main/java/me/monster/colors/ColorUtils.java
Normal file
56
src/main/java/me/monster/colors/ColorUtils.java
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package me.monster.colors;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class ColorUtils {
|
||||||
|
|
||||||
|
public static final String WITH_DELIMITER = "((?<=%1$s)|(?=%1$s))";
|
||||||
|
private static final Pattern HEX_PATTERN = Pattern.compile("(&#[0-9a-fA-F]{6})");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param text The string of text to apply color/effects to
|
||||||
|
* @return Returns a string of text with color/effects applied
|
||||||
|
*/
|
||||||
|
public static String translateColorCodes(@NotNull String text) {
|
||||||
|
//good thing we're stuck on java 8, which means we can't use this (:
|
||||||
|
// String hexColored = HEX_PATTERN.matcher(text)
|
||||||
|
// .replaceAll(match -> "" + ChatColor.of(match.group(1)));
|
||||||
|
Matcher matcher = HEX_PATTERN.matcher(text);
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
String hex = matcher.group(1).substring(1);
|
||||||
|
matcher.appendReplacement(sb, "" + ChatColor.of(hex));
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
|
||||||
|
String hexColored = sb.toString();
|
||||||
|
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', hexColored);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param text The text with color codes that you want to turn into a TextComponent
|
||||||
|
* @return the TextComponent with hex colors and regular colors
|
||||||
|
*/
|
||||||
|
public static TextComponent translateColorCodesToTextComponent(@NotNull String text) {
|
||||||
|
//This is done solely to ensure hex color codes are in the format
|
||||||
|
//fromLegacyText expects:
|
||||||
|
//&#FF0000 -> &x&f&f&0&0&0&0
|
||||||
|
String colored = translateColorCodes(text);
|
||||||
|
|
||||||
|
TextComponent base = new TextComponent();
|
||||||
|
BaseComponent[] converted = TextComponent.fromLegacyText(colored);
|
||||||
|
|
||||||
|
for (BaseComponent comp : converted) {
|
||||||
|
base.addExtra(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/main/java/me/monster/commands/CommandList.java
Normal file
19
src/main/java/me/monster/commands/CommandList.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package me.monster.commands;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A functional interface used to allow the dev to specify how the listing of the subcommands on a core command works.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface CommandList {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sender The thing that ran the command
|
||||||
|
* @param subCommandList A list of all the subcommands you can display
|
||||||
|
*/
|
||||||
|
void displayCommandList(CommandSender sender, List<SubCommand> subCommandList);
|
||||||
|
|
||||||
|
}
|
||||||
71
src/main/java/me/monster/commands/CommandManager.java
Normal file
71
src/main/java/me/monster/commands/CommandManager.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package me.monster.commands;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CommandManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param plugin An instance of your plugin that is using this API. If called within plugin main class, provide this keyword
|
||||||
|
* @param commandName The name of the command
|
||||||
|
* @param commandDescription Description of command as would put it in plugin.yml
|
||||||
|
* @param commandUsage Usage of command as would put it in plugin.yml
|
||||||
|
* @param aliases A String list of aliases(or nothing for overloaded method)
|
||||||
|
* @param subcommands Class reference to each SubCommand you create for this core command
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static void createCoreCommand(JavaPlugin plugin,
|
||||||
|
String commandName,
|
||||||
|
String commandDescription,
|
||||||
|
String commandUsage,
|
||||||
|
@Nullable CommandList commandList,
|
||||||
|
List<String> aliases,
|
||||||
|
Class<? extends SubCommand>... subcommands) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
|
||||||
|
ArrayList<SubCommand> commands = new ArrayList<>();
|
||||||
|
|
||||||
|
Arrays.stream(subcommands).map(subcommand -> {
|
||||||
|
try {
|
||||||
|
Constructor<? extends SubCommand> constructor = subcommand.getConstructor();
|
||||||
|
return constructor.newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).forEach(commands::add);
|
||||||
|
|
||||||
|
//THANK YOU OZZYMAR <3 YOU'RE THE HOMIE
|
||||||
|
Field commandField = plugin.getServer().getClass().getDeclaredField("commandMap");
|
||||||
|
commandField.setAccessible(true);
|
||||||
|
CommandMap commandMap = (CommandMap) commandField.get(plugin.getServer());
|
||||||
|
commandMap.register(commandName, new CoreCommand(commandName, commandDescription, commandUsage, commandList, aliases, commands));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param plugin An instance of your plugin that is using this API. If called within plugin main class, provide this keyword
|
||||||
|
* @param commandName The name of the command
|
||||||
|
* @param commandDescription Description of command as would put it in plugin.yml
|
||||||
|
* @param commandUsage Usage of command as would put it in plugin.yml
|
||||||
|
* @param subcommands Class reference to each SubCommand you create for this core command
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static void createCoreCommand(JavaPlugin plugin,
|
||||||
|
String commandName,
|
||||||
|
String commandDescription,
|
||||||
|
String commandUsage,
|
||||||
|
@Nullable CommandList commandList,
|
||||||
|
Class<? extends SubCommand>... subcommands) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
createCoreCommand(plugin, commandName, commandDescription, commandUsage, commandList, Collections.singletonList(""), subcommands);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
84
src/main/java/me/monster/commands/CoreCommand.java
Normal file
84
src/main/java/me/monster/commands/CoreCommand.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package me.monster.commands;
|
||||||
|
|
||||||
|
import me.monster.colors.ColorUtils;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CoreCommand extends Command {
|
||||||
|
|
||||||
|
private final ArrayList<SubCommand> subcommands;
|
||||||
|
private final CommandList commandList;
|
||||||
|
|
||||||
|
public CoreCommand(String name, String description, String usageMessage, CommandList commandList, List<String> aliases, ArrayList<SubCommand> subCommands) {
|
||||||
|
super(name, description, usageMessage, aliases);
|
||||||
|
//Get the subcommands so we can access them in the command manager class(here)
|
||||||
|
this.subcommands = subCommands;
|
||||||
|
this.commandList = commandList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<SubCommand> getSubCommands() {
|
||||||
|
return subcommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) {
|
||||||
|
if (sender.hasPermission("redmc.manage")) {
|
||||||
|
if (args.length > 0) {
|
||||||
|
for (int i = 0; i < getSubCommands().size(); i++) {
|
||||||
|
if (args[0].equalsIgnoreCase(getSubCommands().get(i).getName()) || (getSubCommands().get(i).getAliases() != null && getSubCommands().get(i).getAliases().contains(args[0]))) {
|
||||||
|
getSubCommands().get(i).perform(sender, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (commandList == null) {
|
||||||
|
sender.sendMessage(ColorUtils.translateColorCodes("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"));
|
||||||
|
for (SubCommand subcommand : subcommands) {
|
||||||
|
sender.sendMessage(ColorUtils.translateColorCodes(subcommand.getSyntax() + " - " + subcommand.getDescription()));
|
||||||
|
}
|
||||||
|
sender.sendMessage(ColorUtils.translateColorCodes("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"));
|
||||||
|
} else {
|
||||||
|
commandList.displayCommandList(sender, subcommands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
if (sender.hasPermission("redmc.manage")) {
|
||||||
|
if (args.length == 1) { //prank <subcommand> <args>
|
||||||
|
ArrayList<String> subcommandsArguments = new ArrayList<>();
|
||||||
|
for (int i = 0; i < getSubCommands().size(); i++) {
|
||||||
|
subcommandsArguments.add(getSubCommands().get(i).getName());
|
||||||
|
}
|
||||||
|
return subcommandsArguments;
|
||||||
|
} else if (args.length >= 2) {
|
||||||
|
for (int i = 0; i < getSubCommands().size(); i++) {
|
||||||
|
if (args[0].equalsIgnoreCase(getSubCommands().get(i).getName())) {
|
||||||
|
List<String> subCommandArgs = getSubCommands().get(i).getSubcommandArguments(
|
||||||
|
(Player) sender, args
|
||||||
|
);
|
||||||
|
|
||||||
|
if (subCommandArgs != null)
|
||||||
|
return subCommandArgs;
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
src/main/java/me/monster/commands/SubCommand.java
Normal file
47
src/main/java/me/monster/commands/SubCommand.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package me.monster.commands;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subcommand like: /corecommand subcommand args
|
||||||
|
* A further example: /chunkcollector buy - buy would be the subcommand that opens a buy menu in that plugin
|
||||||
|
*/
|
||||||
|
public abstract class SubCommand {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The name of the subcommand
|
||||||
|
*/
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The aliases that can be used for this command. Can be null
|
||||||
|
*/
|
||||||
|
public abstract List<String> getAliases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A description of what the subcommand does to be displayed
|
||||||
|
*/
|
||||||
|
public abstract String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An example of how to use the subcommand
|
||||||
|
*/
|
||||||
|
public abstract String getSyntax();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sender The thing that ran the command
|
||||||
|
* @param args The args passed into the command when run
|
||||||
|
*/
|
||||||
|
public abstract void perform(CommandSender sender, String[] args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player who ran the command
|
||||||
|
* @param args The args passed into the command when run
|
||||||
|
* @return A list of arguments to be suggested for autocomplete
|
||||||
|
*/
|
||||||
|
public abstract List<String> getSubcommandArguments(Player player, String[] args);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package me.monster.exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
public class MenuManagerException extends Exception {
|
||||||
|
|
||||||
|
public MenuManagerException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MenuManagerException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MenuManagerException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MenuManagerException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package me.monster.exceptions;
|
||||||
|
|
||||||
|
public class MenuManagerNotSetupException extends Exception {
|
||||||
|
}
|
||||||
276
src/main/java/me/monster/heads/SkullCreator.java
Normal file
276
src/main/java/me/monster/heads/SkullCreator.java
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
package me.monster.heads;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.Skull;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A library for the Bukkit API to create player skulls
|
||||||
|
* from names, base64 strings, and texture URLs.
|
||||||
|
* <p>
|
||||||
|
* Does not use any NMS code, and should work across all versions.
|
||||||
|
*
|
||||||
|
* @author Dean B on 12/28/2016.
|
||||||
|
*/
|
||||||
|
public class SkullCreator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a player's name.
|
||||||
|
*
|
||||||
|
* @param name The Player's name
|
||||||
|
* @return The head of the Player
|
||||||
|
* @deprecated names don't make for good identifiers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static ItemStack itemFromName(String name) {
|
||||||
|
ItemStack item = getPlayerSkullItem();
|
||||||
|
|
||||||
|
return itemWithName(item, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a player's name.
|
||||||
|
*
|
||||||
|
* @param item The item to apply the name to
|
||||||
|
* @param name The Player's name
|
||||||
|
* @return The head of the Player
|
||||||
|
* @deprecated names don't make for good identifiers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static ItemStack itemWithName(ItemStack item, String name) {
|
||||||
|
notNull(item, "item");
|
||||||
|
notNull(name, "name");
|
||||||
|
|
||||||
|
return Bukkit.getUnsafe().modifyItemStack(item,
|
||||||
|
"{SkullOwner:\"" + name + "\"}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull with a UUID. 1.13 only.
|
||||||
|
*
|
||||||
|
* @param id The Player's UUID
|
||||||
|
* @return The head of the Player
|
||||||
|
*/
|
||||||
|
public static ItemStack itemFromUuid(UUID id) {
|
||||||
|
ItemStack item = getPlayerSkullItem();
|
||||||
|
|
||||||
|
return itemWithUuid(item, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a UUID. 1.13 only.
|
||||||
|
*
|
||||||
|
* @param item The item to apply the name to
|
||||||
|
* @param id The Player's UUID
|
||||||
|
* @return The head of the Player
|
||||||
|
*/
|
||||||
|
public static ItemStack itemWithUuid(ItemStack item, UUID id) {
|
||||||
|
notNull(item, "item");
|
||||||
|
notNull(id, "id");
|
||||||
|
|
||||||
|
SkullMeta meta = (SkullMeta) item.getItemMeta();
|
||||||
|
Objects.requireNonNull(meta).setOwningPlayer(Bukkit.getOfflinePlayer(id));
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a Mojang server URL.
|
||||||
|
*
|
||||||
|
* @param url The URL of the Mojang skin
|
||||||
|
* @return The head associated with the URL
|
||||||
|
*/
|
||||||
|
public static ItemStack itemFromUrl(String url) {
|
||||||
|
ItemStack item = getPlayerSkullItem();
|
||||||
|
|
||||||
|
return itemWithUrl(item, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a Mojang server URL.
|
||||||
|
*
|
||||||
|
* @param item The item to apply the skin to
|
||||||
|
* @param url The URL of the Mojang skin
|
||||||
|
* @return The head associated with the URL
|
||||||
|
*/
|
||||||
|
public static ItemStack itemWithUrl(ItemStack item, String url) {
|
||||||
|
notNull(item, "item");
|
||||||
|
notNull(url, "url");
|
||||||
|
|
||||||
|
return itemWithBase64(item, urlToBase64(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player skull based on a base64 string containing the link to the skin.
|
||||||
|
*
|
||||||
|
* @param base64 The base64 string containing the texture
|
||||||
|
* @return The head with a custom texture
|
||||||
|
*/
|
||||||
|
public static ItemStack itemFromBase64(String base64) {
|
||||||
|
ItemStack item = getPlayerSkullItem();
|
||||||
|
return itemWithBase64(item, base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the base64 string to the ItemStack.
|
||||||
|
*
|
||||||
|
* @param item The ItemStack to put the base64 onto
|
||||||
|
* @param base64 The base64 string containing the texture
|
||||||
|
* @return The head with a custom texture
|
||||||
|
*/
|
||||||
|
public static ItemStack itemWithBase64(ItemStack item, String base64) {
|
||||||
|
notNull(item, "item");
|
||||||
|
notNull(base64, "base64");
|
||||||
|
|
||||||
|
UUID hashAsId = new UUID(base64.hashCode(), base64.hashCode());
|
||||||
|
return Bukkit.getUnsafe().modifyItemStack(item,
|
||||||
|
"{SkullOwner:{Id:\"" + hashAsId + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the block to a skull with the given name.
|
||||||
|
*
|
||||||
|
* @param block The block to set
|
||||||
|
* @param name The player to set it to
|
||||||
|
* @deprecated names don't make for good identifiers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static void blockWithName(Block block, String name) {
|
||||||
|
notNull(block, "block");
|
||||||
|
notNull(name, "name");
|
||||||
|
|
||||||
|
setBlockType(block);
|
||||||
|
((Skull) block.getState()).setOwningPlayer(Bukkit.getOfflinePlayer(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the block to a skull with the given UUID.
|
||||||
|
*
|
||||||
|
* @param block The block to set
|
||||||
|
* @param id The player to set it to
|
||||||
|
*/
|
||||||
|
public static void blockWithUuid(Block block, UUID id) {
|
||||||
|
notNull(block, "block");
|
||||||
|
notNull(id, "id");
|
||||||
|
|
||||||
|
setBlockType(block);
|
||||||
|
((Skull) block.getState()).setOwningPlayer(Bukkit.getOfflinePlayer(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the block to a skull with the given UUID.
|
||||||
|
*
|
||||||
|
* @param block The block to set
|
||||||
|
* @param url The mojang URL to set it to use
|
||||||
|
*/
|
||||||
|
public static void blockWithUrl(Block block, String url) {
|
||||||
|
notNull(block, "block");
|
||||||
|
notNull(url, "url");
|
||||||
|
|
||||||
|
blockWithBase64(block, urlToBase64(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the block to a skull with the given UUID.
|
||||||
|
*
|
||||||
|
* @param block The block to set
|
||||||
|
* @param base64 The base64 to set it to use
|
||||||
|
*/
|
||||||
|
public static void blockWithBase64(Block block, String base64) {
|
||||||
|
notNull(block, "block");
|
||||||
|
notNull(base64, "base64");
|
||||||
|
|
||||||
|
UUID hashAsId = new UUID(base64.hashCode(), base64.hashCode());
|
||||||
|
|
||||||
|
String args = String.format(
|
||||||
|
"%d %d %d %s",
|
||||||
|
block.getX(),
|
||||||
|
block.getY(),
|
||||||
|
block.getZ(),
|
||||||
|
"{Owner:{Id:\"" + hashAsId + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newerApi()) {
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "data merge block " + args);
|
||||||
|
} else {
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "blockdata " + args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean newerApi() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Material.valueOf("PLAYER_HEAD");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) { // If PLAYER_HEAD doesn't exist
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack getPlayerSkullItem() {
|
||||||
|
if (newerApi()) {
|
||||||
|
return new ItemStack(Material.valueOf("PLAYER_HEAD"));
|
||||||
|
} else {
|
||||||
|
return new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (byte) 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setBlockType(Block block) {
|
||||||
|
try {
|
||||||
|
block.setType(Material.valueOf("PLAYER_HEAD"), false);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
block.setType(Material.valueOf("SKULL"), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void notNull(Object o, String name) {
|
||||||
|
if (o == null) {
|
||||||
|
throw new NullPointerException(name + " should not be null!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String urlToBase64(String url) {
|
||||||
|
|
||||||
|
URI actualUrl;
|
||||||
|
try {
|
||||||
|
actualUrl = new URI(url);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
String toEncode = "{\"textures\":{\"SKIN\":{\"url\":\"" + actualUrl + "\"}}}";
|
||||||
|
return Base64.getEncoder().encodeToString(toEncode.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Format for skull
|
||||||
|
{
|
||||||
|
display:{
|
||||||
|
Name:"Cheese"
|
||||||
|
},
|
||||||
|
SkullOwner:{
|
||||||
|
Id:"9c919b83-f3fe-456f-a824-7d1d08cc8bd2",
|
||||||
|
Properties:{
|
||||||
|
textures:[
|
||||||
|
{
|
||||||
|
Value:"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTU1ZDYxMWE4NzhlODIxMjMxNzQ5YjI5NjU3MDhjYWQ5NDI2NTA2NzJkYjA5ZTI2ODQ3YTg4ZTJmYWMyOTQ2In19fQ=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
36
src/main/java/me/monster/items/ItemUtils.java
Normal file
36
src/main/java/me/monster/items/ItemUtils.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package me.monster.items;
|
||||||
|
|
||||||
|
import me.monster.colors.ColorUtils;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for Utilities related to Minecraft/Bukkit Items
|
||||||
|
*/
|
||||||
|
public class ItemUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param material The material to base the ItemStack on
|
||||||
|
* @param displayName The display name of the ItemStack
|
||||||
|
* @param lore The lore of the ItemStack, with the Strings being automatically color coded with ColorTranslator
|
||||||
|
* @return The constructed ItemStack object
|
||||||
|
*/
|
||||||
|
public static ItemStack makeItem(Material material, String displayName, String... lore) {
|
||||||
|
|
||||||
|
ItemStack item = new ItemStack(material);
|
||||||
|
ItemMeta itemMeta = item.getItemMeta();
|
||||||
|
assert itemMeta != null;
|
||||||
|
itemMeta.setDisplayName(displayName);
|
||||||
|
|
||||||
|
//Automatically translate color codes provided
|
||||||
|
itemMeta.setLore(Arrays.stream(lore).map(ColorUtils::translateColorCodes).collect(Collectors.toList()));
|
||||||
|
item.setItemMeta(itemMeta);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
141
src/main/java/me/monster/menu/Menu.java
Normal file
141
src/main/java/me/monster/menu/Menu.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package me.monster.menu;
|
||||||
|
|
||||||
|
import me.monster.colors.ColorUtils;
|
||||||
|
import me.monster.exceptions.MenuManagerException;
|
||||||
|
import me.monster.exceptions.MenuManagerNotSetupException;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Defines the behavior and attributes of all menus in our plugin
|
||||||
|
*/
|
||||||
|
public abstract class Menu implements InventoryHolder {
|
||||||
|
|
||||||
|
//Protected values that can be accessed in the menus
|
||||||
|
protected PlayerMenuUtility playerMenuUtility;
|
||||||
|
protected Player player;
|
||||||
|
protected Inventory inventory;
|
||||||
|
protected ItemStack FILLER_GLASS = makeItem(Material.GRAY_STAINED_GLASS_PANE, " ");
|
||||||
|
|
||||||
|
//Constructor for Menu. Pass in a PlayerMenuUtility so that
|
||||||
|
// we have information on whose menu this is and
|
||||||
|
// what info is to be transferred
|
||||||
|
public Menu(PlayerMenuUtility playerMenuUtility) {
|
||||||
|
this.playerMenuUtility = playerMenuUtility;
|
||||||
|
this.player = playerMenuUtility.getOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
//let each menu decide their name
|
||||||
|
public abstract String getMenuName();
|
||||||
|
|
||||||
|
//let each menu decide their slot amount
|
||||||
|
public abstract int getSlots();
|
||||||
|
|
||||||
|
public abstract boolean cancelAllClicks();
|
||||||
|
|
||||||
|
//let each menu decide how the items in the menu will be handled when clicked
|
||||||
|
public abstract void handleMenu(InventoryClickEvent e) throws MenuManagerNotSetupException, MenuManagerException;
|
||||||
|
|
||||||
|
//let each menu decide what items are to be placed in the inventory menu
|
||||||
|
public abstract void setMenuItems();
|
||||||
|
|
||||||
|
//When called, an inventory is created and opened for the player
|
||||||
|
public void open() {
|
||||||
|
//The owner of the inventory created is the Menu itself,
|
||||||
|
// so we are able to reverse engineer the Menu object from the
|
||||||
|
// inventoryHolder in the MenuListener class when handling clicks
|
||||||
|
inventory = Bukkit.createInventory(this, getSlots(), getMenuName());
|
||||||
|
|
||||||
|
//grab all the items specified to be used for this menu and add to inventory
|
||||||
|
this.setMenuItems();
|
||||||
|
|
||||||
|
//open the inventory for the player
|
||||||
|
playerMenuUtility.getOwner().openInventory(inventory);
|
||||||
|
playerMenuUtility.pushMenu(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void back() throws MenuManagerException, MenuManagerNotSetupException {
|
||||||
|
MenuManager.openMenu(playerMenuUtility.lastMenu().getClass(), playerMenuUtility.getOwner());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void reloadItems() {
|
||||||
|
for (int i = 0; i < inventory.getSize(); i++) {
|
||||||
|
inventory.setItem(i, null);
|
||||||
|
}
|
||||||
|
setMenuItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void reload() throws MenuManagerException, MenuManagerNotSetupException {
|
||||||
|
player.closeInventory();
|
||||||
|
MenuManager.openMenu(this.getClass(), player);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Overridden method from the InventoryHolder interface
|
||||||
|
@Override
|
||||||
|
public @NotNull Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will fill all the empty slots with "filler glass"
|
||||||
|
*/
|
||||||
|
//Helpful utility method to fill all remaining slots with "filler glass"
|
||||||
|
public void setFillerGlass() {
|
||||||
|
for (int i = 0; i < getSlots(); i++) {
|
||||||
|
if (inventory.getItem(i) == null) {
|
||||||
|
inventory.setItem(i, FILLER_GLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param itemStack Placed into every empty slot when ran
|
||||||
|
*/
|
||||||
|
public void setFillerGlass(ItemStack itemStack) {
|
||||||
|
for (int i = 0; i < getSlots(); i++) {
|
||||||
|
if (inventory.getItem(i) == null) {
|
||||||
|
inventory.setItem(i, itemStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param material The material to base the ItemStack on
|
||||||
|
* @param displayName The display name of the ItemStack
|
||||||
|
* @param lore The lore of the ItemStack, with the Strings being automatically color coded with ColorTranslator
|
||||||
|
* @return The constructed ItemStack object
|
||||||
|
*/
|
||||||
|
public ItemStack makeItem(Material material, String displayName, String... lore) {
|
||||||
|
|
||||||
|
ItemStack item = new ItemStack(material);
|
||||||
|
ItemMeta itemMeta = item.getItemMeta();
|
||||||
|
assert itemMeta != null;
|
||||||
|
itemMeta.setDisplayName(displayName);
|
||||||
|
|
||||||
|
//Automatically translate color codes provided
|
||||||
|
itemMeta.setLore(Arrays.stream(lore).map(ColorUtils::translateColorCodes).collect(Collectors.toList()));
|
||||||
|
item.setItemMeta(itemMeta);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player closes this menu
|
||||||
|
* Override this method to handle menu closing events
|
||||||
|
*/
|
||||||
|
public void handleMenuClose() {
|
||||||
|
// Default empty implementation
|
||||||
|
// Subclasses can override this if they want to handle menu closing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
53
src/main/java/me/monster/menu/MenuListener.java
Normal file
53
src/main/java/me/monster/menu/MenuListener.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package me.monster.menu;
|
||||||
|
|
||||||
|
|
||||||
|
import me.monster.exceptions.MenuManagerException;
|
||||||
|
import me.monster.exceptions.MenuManagerNotSetupException;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
|
||||||
|
public class MenuListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onMenuClick(InventoryClickEvent e) {
|
||||||
|
|
||||||
|
InventoryHolder holder = e.getInventory().getHolder();
|
||||||
|
//If the inventoryholder of the inventory clicked on
|
||||||
|
// is an instance of Menu, then gg. The reason that
|
||||||
|
// an InventoryHolder can be a Menu is because our Menu
|
||||||
|
// class implements InventoryHolder!!
|
||||||
|
if (holder instanceof Menu menu) {
|
||||||
|
if (e.getCurrentItem() == null) { //deal with null exceptions
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu.cancelAllClicks()) {
|
||||||
|
e.setCancelled(true); //prevent them from fucking with the inventory
|
||||||
|
}
|
||||||
|
|
||||||
|
//Call the handleMenu object which takes the event and processes it
|
||||||
|
try {
|
||||||
|
menu.handleMenu(e);
|
||||||
|
} catch (MenuManagerNotSetupException menuManagerNotSetupException) {
|
||||||
|
System.out.println(ChatColor.RED + "THE MENU MANAGER HAS NOT BEEN CONFIGURED. CALL MENUMANAGER.SETUP()");
|
||||||
|
} catch (MenuManagerException menuManagerException) {
|
||||||
|
menuManagerException.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onMenuClose(InventoryCloseEvent e) {
|
||||||
|
InventoryHolder holder = e.getInventory().getHolder();
|
||||||
|
|
||||||
|
if (holder instanceof Menu menu) {
|
||||||
|
menu.handleMenuClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
src/main/java/me/monster/menu/MenuManager.java
Normal file
85
src/main/java/me/monster/menu/MenuManager.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package me.monster.menu;
|
||||||
|
|
||||||
|
import me.monster.exceptions.MenuManagerException;
|
||||||
|
import me.monster.exceptions.MenuManagerNotSetupException;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.RegisteredListener;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to interface with the Menu Manager API
|
||||||
|
*/
|
||||||
|
public class MenuManager {
|
||||||
|
|
||||||
|
//each player will be assigned their own PlayerMenuUtility object
|
||||||
|
private static final HashMap<Player, PlayerMenuUtility> playerMenuUtilityMap = new HashMap<>();
|
||||||
|
private static boolean isSetup = false;
|
||||||
|
|
||||||
|
private static void registerMenuListener(Server server, Plugin plugin) {
|
||||||
|
boolean isAlreadyRegistered = false;
|
||||||
|
for (RegisteredListener rl : InventoryClickEvent.getHandlerList().getRegisteredListeners()) {
|
||||||
|
if (rl.getListener() instanceof MenuListener) {
|
||||||
|
isAlreadyRegistered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAlreadyRegistered) {
|
||||||
|
server.getPluginManager().registerEvents(new MenuListener(), plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param server The instance of your server. Provide by calling getServer()
|
||||||
|
* @param plugin The instance of the plugin using this API. Can provide in plugin class by passing this keyword
|
||||||
|
*/
|
||||||
|
public static void setup(Server server, Plugin plugin) {
|
||||||
|
plugin.getLogger().info("Menu Manager has been setup");
|
||||||
|
|
||||||
|
registerMenuListener(server, plugin);
|
||||||
|
isSetup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param menuClass The class reference of the Menu you want to open for a player
|
||||||
|
* @param player The player to open the menu for
|
||||||
|
* @throws MenuManagerNotSetupException Thrown if the setup() method has not been called and used properly
|
||||||
|
*/
|
||||||
|
public static void openMenu(Class<? extends Menu> menuClass, Player player) throws MenuManagerException, MenuManagerNotSetupException {
|
||||||
|
try {
|
||||||
|
menuClass.getConstructor(PlayerMenuUtility.class).newInstance(getPlayerMenuUtility(player)).open();
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new MenuManagerException("Failed to instantiate menu class", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new MenuManagerException("Illegal access while trying to instantiate menu class", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new MenuManagerException("An error occurred while trying to invoke the menu class constructor", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new MenuManagerException("The menu class constructor could not be found", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlayerMenuUtility getPlayerMenuUtility(Player p) throws MenuManagerNotSetupException {
|
||||||
|
if (!isSetup) {
|
||||||
|
throw new MenuManagerNotSetupException();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerMenuUtility playerMenuUtility;
|
||||||
|
if (!(playerMenuUtilityMap.containsKey(p))) { //See if the player has a pmu "saved" for them
|
||||||
|
|
||||||
|
//Construct PMU
|
||||||
|
playerMenuUtility = new PlayerMenuUtility(p);
|
||||||
|
playerMenuUtilityMap.put(p, playerMenuUtility);
|
||||||
|
|
||||||
|
return playerMenuUtility;
|
||||||
|
} else {
|
||||||
|
return playerMenuUtilityMap.get(p); //Return the object by using the provided player
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
201
src/main/java/me/monster/menu/PaginatedMenu.java
Normal file
201
src/main/java/me/monster/menu/PaginatedMenu.java
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
package me.monster.menu;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class PaginatedMenu extends Menu {
|
||||||
|
|
||||||
|
//The items being paginated
|
||||||
|
protected List<Object> data;
|
||||||
|
|
||||||
|
//Keep track of what page the menu is on
|
||||||
|
protected int page = 0;
|
||||||
|
//28 is max items because with the border set below,
|
||||||
|
//28 empty slots are remaining.
|
||||||
|
protected int maxItemsPerPage = 28;
|
||||||
|
|
||||||
|
// Add cache field
|
||||||
|
private List<ItemStack> cachedItems;
|
||||||
|
|
||||||
|
public PaginatedMenu(PlayerMenuUtility playerMenuUtility) {
|
||||||
|
super(playerMenuUtility);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A list of ItemStacks that you want to be placed in the menu. This is the data that will be paginated
|
||||||
|
* You can also use this as a way to convert your data to items if you need to
|
||||||
|
*/
|
||||||
|
public abstract List<ItemStack> dataToItems();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A hashmap of items you want to be placed in the paginated menu border. This will override any items already placed by default. Key = slot, Value = Item
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public abstract HashMap<Integer, ItemStack> getCustomMenuBorderItems();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the border and menu buttons for the menu. Override this method to provide a custom menu border or specify custom items in customMenuBorderItems()
|
||||||
|
*/
|
||||||
|
protected void addMenuBorder() {
|
||||||
|
// First page button
|
||||||
|
inventory.setItem(47, makeItem(Material.DARK_OAK_BUTTON, ChatColor.GREEN + "First Page"));
|
||||||
|
// Previous page button
|
||||||
|
inventory.setItem(48, makeItem(Material.DARK_OAK_BUTTON, ChatColor.GREEN + "Previous"));
|
||||||
|
// Close button
|
||||||
|
inventory.setItem(49, makeItem(Material.BARRIER, ChatColor.DARK_RED + "Close"));
|
||||||
|
// Next page button
|
||||||
|
inventory.setItem(50, makeItem(Material.DARK_OAK_BUTTON, ChatColor.GREEN + "Next"));
|
||||||
|
// Last page button
|
||||||
|
inventory.setItem(51, makeItem(Material.DARK_OAK_BUTTON, ChatColor.GREEN + "Last Page"));
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
if (inventory.getItem(i) == null) {
|
||||||
|
inventory.setItem(i, super.FILLER_GLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.setItem(17, super.FILLER_GLASS);
|
||||||
|
inventory.setItem(18, super.FILLER_GLASS);
|
||||||
|
inventory.setItem(26, super.FILLER_GLASS);
|
||||||
|
inventory.setItem(27, super.FILLER_GLASS);
|
||||||
|
inventory.setItem(35, super.FILLER_GLASS);
|
||||||
|
inventory.setItem(36, super.FILLER_GLASS);
|
||||||
|
|
||||||
|
for (int i = 44; i < 54; i++) {
|
||||||
|
if (inventory.getItem(i) == null) {
|
||||||
|
inventory.setItem(i, super.FILLER_GLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//place the custom items if they exist
|
||||||
|
if (getCustomMenuBorderItems() != null) {
|
||||||
|
getCustomMenuBorderItems().forEach((integer, itemStack) -> inventory.setItem(integer, itemStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the paginated items, using cache if available
|
||||||
|
* @return List of ItemStacks to display
|
||||||
|
*/
|
||||||
|
protected List<ItemStack> getItems() {
|
||||||
|
if (cachedItems == null) {
|
||||||
|
cachedItems = dataToItems();
|
||||||
|
}
|
||||||
|
return cachedItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the item cache, forcing items to be reloaded next time
|
||||||
|
*/
|
||||||
|
protected void invalidateCache() {
|
||||||
|
cachedItems = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place each item in the paginated menu, automatically coded by default but override if you want custom functionality. Calls the loopCode() method you define for each item returned in the getData() method
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setMenuItems() {
|
||||||
|
addMenuBorder();
|
||||||
|
|
||||||
|
List<ItemStack> items = getItems(); // Use cached items
|
||||||
|
|
||||||
|
int slot = 10;
|
||||||
|
for (int i = 0; i < maxItemsPerPage; i++) {
|
||||||
|
int index = maxItemsPerPage * page + i;
|
||||||
|
if (index >= items.size()) break;
|
||||||
|
|
||||||
|
if (slot % 9 == 8) slot += 2;
|
||||||
|
|
||||||
|
inventory.setItem(slot, items.get(index));
|
||||||
|
slot++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if successful, false if already on the first page
|
||||||
|
*/
|
||||||
|
public boolean prevPage() {
|
||||||
|
if (page == 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
page = page - 1;
|
||||||
|
reloadItems();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if successful, false if already on the last page
|
||||||
|
*/
|
||||||
|
public boolean nextPage() {
|
||||||
|
int totalItems = getItems().size(); // Use cached items
|
||||||
|
int lastPageNumber = (totalItems - 1) / maxItemsPerPage;
|
||||||
|
|
||||||
|
if (page < lastPageNumber) {
|
||||||
|
page++;
|
||||||
|
reloadItems();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxItemsPerPage() {
|
||||||
|
return maxItemsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentPage() {
|
||||||
|
return page + 1; // Convert to 1-based page numbers for display
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalPages() {
|
||||||
|
return ((getItems().size() - 1) / maxItemsPerPage) + 1; // Use cached items
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open() {
|
||||||
|
invalidateCache(); // Force items to be reloaded when menu opens
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the menu data and reloads items while keeping the menu open
|
||||||
|
*/
|
||||||
|
public void refreshData() {
|
||||||
|
invalidateCache();
|
||||||
|
reloadItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current page to the first page (0)
|
||||||
|
* @return true if the page was changed, false if already on first page
|
||||||
|
*/
|
||||||
|
public boolean firstPage() {
|
||||||
|
if (page == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
page = 0;
|
||||||
|
reloadItems();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current page to the last page
|
||||||
|
* @return true if the page was changed, false if already on last page
|
||||||
|
*/
|
||||||
|
public boolean lastPage() {
|
||||||
|
int lastPageNum = (getItems().size() - 1) / maxItemsPerPage;
|
||||||
|
if (page == lastPageNum) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
page = lastPageNum;
|
||||||
|
reloadItems();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/main/java/me/monster/menu/PlayerMenuUtility.java
Normal file
87
src/main/java/me/monster/menu/PlayerMenuUtility.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package me.monster.menu;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Companion class to all menus. This is needed to pass information across the entire
|
||||||
|
menu system no matter how many inventories are opened or closed.
|
||||||
|
|
||||||
|
Each player has one of these objects, and only one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class PlayerMenuUtility {
|
||||||
|
|
||||||
|
private final Player owner;
|
||||||
|
private final HashMap<String, Object> dataMap = new HashMap<>();
|
||||||
|
private final Stack<Menu> history = new Stack<>();
|
||||||
|
|
||||||
|
public PlayerMenuUtility(Player p) {
|
||||||
|
this.owner = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param identifier A key to store the data by
|
||||||
|
* @param data The data itself to be stored
|
||||||
|
*/
|
||||||
|
public void setData(String identifier, Object data) {
|
||||||
|
this.dataMap.put(identifier, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(Enum identifier, Object data) {
|
||||||
|
this.dataMap.put(identifier.toString(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param identifier The key for the data stored in the PMC
|
||||||
|
* @return The retrieved value or null if not found
|
||||||
|
*/
|
||||||
|
public Object getData(String identifier) {
|
||||||
|
return this.dataMap.get(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData(Enum identifier) {
|
||||||
|
return this.dataMap.get(identifier.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getData(String identifier, Class<T> classRef) {
|
||||||
|
|
||||||
|
Object obj = this.dataMap.get(identifier);
|
||||||
|
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return classRef.cast(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getData(Enum identifier, Class<T> classRef) {
|
||||||
|
|
||||||
|
Object obj = this.dataMap.get(identifier.toString());
|
||||||
|
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return classRef.cast(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Get the previous menu that was opened for the player
|
||||||
|
*/
|
||||||
|
public Menu lastMenu() {
|
||||||
|
this.history.pop(); //Makes back() work for some reason
|
||||||
|
return this.history.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushMenu(Menu menu) {
|
||||||
|
this.history.push(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
8
src/main/resources/plugin.yml
Normal file
8
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
name: RedMC-API
|
||||||
|
version: '1.0'
|
||||||
|
main: me.monster.Main
|
||||||
|
api-version: '1.21'
|
||||||
|
prefix: RedMC
|
||||||
|
load: STARTUP
|
||||||
|
authors: [ 41ms_ ]
|
||||||
|
website: 41ms.fr
|
||||||
Reference in New Issue
Block a user