refactor: Java 21 support, config/API updates, GUI polish
This commit is contained in:
parent
bfdf197de4
commit
ceb4c804b7
76 changed files with 1210 additions and 999 deletions
|
|
@ -13,14 +13,31 @@ java {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile> {
|
||||||
|
options.release.set(21)
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
maven("https://repo.papermc.io/repository/maven-public/")
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
|
||||||
|
// PlaceholderAPI
|
||||||
|
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||||
|
|
||||||
|
// WorldGuard / WorldEdit
|
||||||
|
maven("https://maven.enginehub.org/repo/")
|
||||||
|
|
||||||
|
// CodeMC (DecentHolograms)
|
||||||
|
maven("https://repo.codemc.io/repository/maven-public/")
|
||||||
|
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoAPI: libs/lolib*.jar — fileTree индексируется Gradle / Java LS стабильнее, чем files(singleJar)
|
val lolibTree = fileTree("libs") {
|
||||||
val lolibTree = fileTree("libs") { include("lolib*.jar") }
|
include("lolib*.jar")
|
||||||
|
}
|
||||||
|
|
||||||
if (lolibTree.files.isEmpty()) {
|
if (lolibTree.files.isEmpty()) {
|
||||||
throw GradleException(
|
throw GradleException(
|
||||||
"Missing libs/lolib*.jar — add LoAPI fat jar to ${rootProject.file("libs").absolutePath}"
|
"Missing libs/lolib*.jar — add LoAPI fat jar to ${rootProject.file("libs").absolutePath}"
|
||||||
|
|
@ -28,45 +45,59 @@ if (lolibTree.files.isEmpty()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Paper API 1.21.4 (includes Adventure API)
|
|
||||||
|
// Paper
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
// LoAPI (local)
|
// Local API
|
||||||
implementation(lolibTree)
|
implementation(lolibTree)
|
||||||
|
|
||||||
// Runtime dependencies (loaded via DependencyManager from LoAPI)
|
// Commons
|
||||||
// These are marked as compileOnly because they will be downloaded at runtime
|
|
||||||
compileOnly("org.apache.commons:commons-math3:3.6.1")
|
compileOnly("org.apache.commons:commons-math3:3.6.1")
|
||||||
compileOnly("commons-io:commons-io:2.18.0")
|
compileOnly("commons-io:commons-io:2.18.0")
|
||||||
|
|
||||||
// Adventure API (included in Paper, but explicit for clarity)
|
// Adventure
|
||||||
compileOnly("net.kyori:adventure-api:4.17.0")
|
compileOnly("net.kyori:adventure-api:4.17.0")
|
||||||
compileOnly("net.kyori:adventure-text-minimessage:4.17.0")
|
compileOnly("net.kyori:adventure-text-minimessage:4.17.0")
|
||||||
|
|
||||||
// Optional plugin integrations (soft dependencies)
|
// PlaceholderAPI
|
||||||
|
compileOnly("me.clip:placeholderapi:2.11.6")
|
||||||
|
|
||||||
|
// WorldGuard + WorldEdit
|
||||||
|
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.13")
|
||||||
|
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.3.10")
|
||||||
|
|
||||||
|
|
||||||
|
// Optional
|
||||||
// compileOnly("com.github.oraxen:oraxen:1.180.0")
|
// compileOnly("com.github.oraxen:oraxen:1.180.0")
|
||||||
// compileOnly("com.github.LoneDev6:api-itemsadder:3.6.4")
|
// compileOnly("com.github.LoneDev6:api-itemsadder:3.6.4")
|
||||||
|
|
||||||
// Test dependencies
|
// Tests
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter:5.11.4")
|
testImplementation("org.junit.jupiter:junit-jupiter:5.11.4")
|
||||||
testImplementation("io.kotest:kotest-runner-junit5:5.9.1")
|
testImplementation("io.kotest:kotest-runner-junit5:5.9.1")
|
||||||
testImplementation("io.kotest:kotest-assertions-core:5.9.1")
|
testImplementation("io.kotest:kotest-assertions-core:5.9.1")
|
||||||
testImplementation("io.kotest:kotest-property:5.9.1")
|
testImplementation("io.kotest:kotest-property:5.9.1")
|
||||||
testImplementation("org.mockito:mockito-core:5.14.2")
|
testImplementation("org.mockito:mockito-core:5.14.2")
|
||||||
|
testImplementation("org.mockito:mockito-inline:5.2.0")
|
||||||
|
|
||||||
|
// Bukkit/Paper API for tests
|
||||||
testImplementation("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
testImplementation("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||||
testImplementation("org.apache.commons:commons-math3:3.6.1")
|
|
||||||
testImplementation("commons-io:commons-io:2.18.0")
|
// Adventure for tests
|
||||||
|
testImplementation("net.kyori:adventure-api:4.17.0")
|
||||||
|
testImplementation("net.kyori:adventure-text-minimessage:4.17.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
archiveClassifier.set("")
|
archiveClassifier.set("")
|
||||||
|
|
||||||
// Relocate LoAPI to avoid conflicts
|
// Temporary: disable relocate to avoid ASM Java 21 bytecode issues
|
||||||
relocate("dev.loki.lomines.libs.lolib", "com.loki.lomines.libs.lolib")
|
// relocate(
|
||||||
|
// "dev.loki.lomines.libs.lolib",
|
||||||
// Don't minimize - causes issues with Java 21
|
// "com.loki.lomines.libs.lolib"
|
||||||
// minimize()
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
build {
|
build {
|
||||||
|
|
@ -82,8 +113,10 @@ tasks {
|
||||||
"version" to version,
|
"version" to version,
|
||||||
"description" to description
|
"description" to description
|
||||||
)
|
)
|
||||||
|
|
||||||
inputs.properties(props)
|
inputs.properties(props)
|
||||||
filteringCharset = "UTF-8"
|
filteringCharset = "UTF-8"
|
||||||
|
|
||||||
filesMatching("plugin.yml") {
|
filesMatching("plugin.yml") {
|
||||||
expand(props)
|
expand(props)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
251
gradlew
vendored
Normal file
251
gradlew
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#!/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.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || 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="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
|
# 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, 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" \
|
||||||
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# 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" "$@"
|
||||||
91
gradlew.bat
vendored
91
gradlew.bat
vendored
|
|
@ -1,7 +1,94 @@
|
||||||
@rem Gradle startup script for Windows
|
@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
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@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
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
java -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
|
||||||
|
@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=
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
|
: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,21 +1,11 @@
|
||||||
package dev.loki.lomines;
|
package dev.loki.lomines;
|
||||||
|
|
||||||
import dev.loki.lomines.command.admin.AdminCommands;
|
import dev.loki.lomines.command.admin.*;
|
||||||
import dev.loki.lomines.command.admin.CopyCommand;
|
|
||||||
import dev.loki.lomines.command.admin.HologramCommands;
|
|
||||||
import dev.loki.lomines.command.admin.InfoCommand;
|
|
||||||
import dev.loki.lomines.command.admin.MaskCommands;
|
|
||||||
import dev.loki.lomines.command.admin.RegionCommands;
|
|
||||||
import dev.loki.lomines.command.admin.StatsCommands;
|
|
||||||
import dev.loki.lomines.command.common.LoMinesTabCompleter;
|
import dev.loki.lomines.command.common.LoMinesTabCompleter;
|
||||||
import dev.loki.lomines.command.player.PlayerCommands;
|
import dev.loki.lomines.command.player.PlayerCommands;
|
||||||
import dev.loki.lomines.command.player.TeleportCommand;
|
import dev.loki.lomines.command.player.TeleportCommand;
|
||||||
import dev.loki.lomines.integration.IntegrationManager;
|
import dev.loki.lomines.integration.IntegrationManager;
|
||||||
import dev.loki.lomines.listener.BlockBreakListener;
|
import dev.loki.lomines.listener.*;
|
||||||
import dev.loki.lomines.listener.GroupGuiListener;
|
|
||||||
import dev.loki.lomines.listener.MineEditGuiListener;
|
|
||||||
import dev.loki.lomines.listener.PlayerInteractListener;
|
|
||||||
import dev.loki.lomines.listener.PlayerJoinListener;
|
|
||||||
import dev.lolib.commands.CommandManager;
|
import dev.lolib.commands.CommandManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,8 @@ public final class BukkitBlockSetter extends BlockSetter {
|
||||||
currentWeight += entry.getValue();
|
currentWeight += entry.getValue();
|
||||||
if (random <= currentWeight) {
|
if (random <= currentWeight) {
|
||||||
// BlockKey is already validated to be a block
|
// BlockKey is already validated to be a block
|
||||||
if (entry.getKey() instanceof BlockKey.Vanilla vanilla) {
|
if (entry.getKey() instanceof BlockKey.Vanilla(Material material)) {
|
||||||
return Bukkit.createBlockData(vanilla.material());
|
return Bukkit.createBlockData(material);
|
||||||
}
|
}
|
||||||
// Fallback for non-vanilla keys in vanilla setter (shouldn't happen)
|
// Fallback for non-vanilla keys in vanilla setter (shouldn't happen)
|
||||||
return Bukkit.createBlockData(Material.STONE);
|
return Bukkit.createBlockData(Material.STONE);
|
||||||
|
|
@ -116,8 +116,8 @@ public final class BukkitBlockSetter extends BlockSetter {
|
||||||
|
|
||||||
// Fallback to first entry
|
// Fallback to first entry
|
||||||
BlockKey firstKey = weights.keySet().iterator().next();
|
BlockKey firstKey = weights.keySet().iterator().next();
|
||||||
if (firstKey instanceof BlockKey.Vanilla vanilla) {
|
if (firstKey instanceof BlockKey.Vanilla(Material material)) {
|
||||||
return Bukkit.createBlockData(vanilla.material());
|
return Bukkit.createBlockData(material);
|
||||||
}
|
}
|
||||||
return Bukkit.createBlockData(Material.STONE);
|
return Bukkit.createBlockData(Material.STONE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,13 @@ package dev.loki.lomines.command.admin;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.core.mine.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.lolilb.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
import dev.lolilb.commands.annotation.Subcommand;
|
import dev.lolib.commands.annotation.Subcommand;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command to copy mine configuration from one mine to another.
|
* Command to copy mine configuration from one mine to another.
|
||||||
*/
|
*/
|
||||||
|
|
@ -53,49 +50,25 @@ public class CopyCommand {
|
||||||
var sourceConfig = fromMine.getConfig();
|
var sourceConfig = fromMine.getConfig();
|
||||||
var targetConfig = toMine.getConfig();
|
var targetConfig = toMine.getConfig();
|
||||||
|
|
||||||
// Copy blocks configuration
|
// Keep target region/name, copy all other sections from source.
|
||||||
targetConfig.blocks().weights().clear();
|
MineConfig newTargetConfig = MineConfig.builder(toMine.getName())
|
||||||
targetConfig.blocks().weights().putAll(sourceConfig.blocks().weights());
|
.region(targetConfig.region())
|
||||||
|
.blocks(sourceConfig.blocks())
|
||||||
|
.reset(sourceConfig.reset())
|
||||||
|
.rewards(sourceConfig.rewards())
|
||||||
|
.teleport(sourceConfig.teleport())
|
||||||
|
.ui(sourceConfig.ui())
|
||||||
|
.worldGuard(sourceConfig.worldGuard())
|
||||||
|
.playerSpawn(sourceConfig.playerSpawn())
|
||||||
|
.build();
|
||||||
|
|
||||||
// Copy reset settings
|
try {
|
||||||
var targetReset = targetConfig.reset();
|
plugin.getMines().updateMineConfig(toMine.getName(), newTargetConfig);
|
||||||
var sourceReset = sourceConfig.reset();
|
} catch (Exception e) {
|
||||||
targetReset.intervalSeconds(sourceReset.intervalSeconds());
|
sender.sendMessage(Component.text("Ошибка сохранения: " + e.getMessage(), NamedTextColor.RED));
|
||||||
targetReset.percentTrigger(sourceReset.percentTrigger());
|
return;
|
||||||
targetReset.percentTriggerEnabled(sourceReset.isPercentTriggerEnabled());
|
|
||||||
targetReset.intervalDisplay(sourceReset.intervalDisplay());
|
|
||||||
|
|
||||||
// Copy teleport and spawn settings
|
|
||||||
var targetTeleport = targetConfig.teleport();
|
|
||||||
var sourceTeleport = sourceConfig.teleport();
|
|
||||||
targetTeleport.enabled(sourceTeleport.enabled());
|
|
||||||
if (sourceTeleport.getLocation().isPresent()) {
|
|
||||||
targetTeleport.setLocation(sourceTeleport.getLocation().get());
|
|
||||||
} else {
|
|
||||||
targetTeleport.setLocation(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetSpawn = targetConfig.playerSpawn();
|
|
||||||
var sourceSpawn = sourceConfig.playerSpawn();
|
|
||||||
targetSpawn.enabled(sourceSpawn.enabled());
|
|
||||||
if (sourceSpawn.getLocation().isPresent()) {
|
|
||||||
targetSpawn.setLocation(sourceSpawn.getLocation().get());
|
|
||||||
} else {
|
|
||||||
targetSpawn.setLocation(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy rewards
|
|
||||||
targetConfig.rewards().entries().clear();
|
|
||||||
targetConfig.rewards().entries().addAll(sourceConfig.rewards().entries());
|
|
||||||
|
|
||||||
// Copy other settings
|
|
||||||
targetConfig.blockPhysics(sourceConfig.isBlockPhysicsEnabled());
|
|
||||||
targetConfig.entitySpawning(sourceConfig.isEntitySpawningEnabled());
|
|
||||||
targetConfig.liquidFlow(sourceConfig.isLiquidFlowEnabled());
|
|
||||||
|
|
||||||
// Save target mine
|
|
||||||
toMine.save();
|
|
||||||
|
|
||||||
sender.sendMessage(Component.text("§aКонфигурация скопирована из §f" + fromMine.getName() +
|
sender.sendMessage(Component.text("§aКонфигурация скопирована из §f" + fromMine.getName() +
|
||||||
" §aв §f" + toMine.getName()));
|
" §aв §f" + toMine.getName()));
|
||||||
sender.sendMessage(Component.text("§7Скопировано:"));
|
sender.sendMessage(Component.text("§7Скопировано:"));
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,21 @@ package dev.loki.lomines.command.admin;
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.integration.hologram.HologramManager;
|
import dev.loki.lomines.integration.hologram.HologramManager;
|
||||||
import dev.lolilb.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
import dev.lolilb.commands.annotation.Subcommand;
|
import dev.lolib.commands.annotation.Subcommand;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commands for managing holograms above mines.
|
* Commands for managing holograms above mines.
|
||||||
*/
|
*/
|
||||||
class HologramCommands {
|
public class HologramCommands {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
private final LoMinesPlugin plugin;
|
||||||
private final HologramManager hologramManager;
|
private final HologramManager hologramManager;
|
||||||
|
|
||||||
HologramCommands(LoMinesPlugin plugin) {
|
public HologramCommands(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.hologramManager = plugin.getHologramManager();
|
this.hologramManager = plugin.getHologramManager();
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +54,6 @@ class HologramCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage(Component.text(
|
sender.sendMessage(Component.text(
|
||||||
"Голограмма для шахты " + mineName + " " + (enable ? "§aвключена" : "§cвыключена")));
|
"Голограмма для шахты " + mineName + " " + (enable ? "§aвключена" : "§cвыключена")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,11 @@ import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.block.BlockKey;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
import dev.loki.lomines.util.location.Cuboid;
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import dev.lolilb.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
import dev.lolilb.commands.annotation.Subcommand;
|
import dev.lolib.commands.annotation.Subcommand;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -65,10 +64,10 @@ public class InfoCommand {
|
||||||
sender.sendMessage(Component.text("§6§lБлоки:"));
|
sender.sendMessage(Component.text("§6§lБлоки:"));
|
||||||
Map<BlockKey, Double> weights = config.blocks().weights();
|
Map<BlockKey, Double> weights = config.blocks().weights();
|
||||||
weights.entrySet().stream()
|
weights.entrySet().stream()
|
||||||
.sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
|
.sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
|
||||||
.limit(10)
|
.limit(10)
|
||||||
.forEach(e -> sender.sendMessage(Component.text(
|
.forEach(e -> sender.sendMessage(Component.text(
|
||||||
"§7 " + formatBlockKey(e.getKey()) + ": §f" + String.format("%.1f", e.getValue() * 100) + "%")));
|
"§7 " + formatBlockKey(e.getKey()) + ": §f" + String.format("%.1f", e.getValue() * 100) + "%")));
|
||||||
if (weights.size() > 10) {
|
if (weights.size() > 10) {
|
||||||
sender.sendMessage(Component.text("§7 ... и ещё " + (weights.size() - 10) + " блоков"));
|
sender.sendMessage(Component.text("§7 ... и ещё " + (weights.size() - 10) + " блоков"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package dev.loki.lomines.command.admin;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mines;
|
import dev.loki.lomines.core.mine.Mines;
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.util.ErrorHandler;
|
import dev.loki.lomines.util.ErrorHandler;
|
||||||
import dev.loki.lomines.util.MessageFormatter;
|
import dev.loki.lomines.util.MessageFormatter;
|
||||||
import dev.lolib.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.data.config.region.RegionConfig;
|
import dev.loki.lomines.data.config.region.RegionConfig;
|
||||||
import dev.loki.lomines.util.location.Cuboid;
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import dev.lolilb.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
import dev.lolilb.commands.annotation.Subcommand;
|
import dev.lolib.commands.annotation.Subcommand;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
|
@ -73,14 +72,15 @@ public class RegionCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
var wandManager = plugin.getGroupWandManager();
|
var wandManager = plugin.getGroupWandManager();
|
||||||
var session = wandManager.getSession(player);
|
var session = wandManager.getSession(player.getUniqueId());
|
||||||
|
int slot = session.getActiveSlot();
|
||||||
if (!session.isComplete()) {
|
var pos1 = session.getPos1(slot);
|
||||||
|
var pos2 = session.getPos2(slot);
|
||||||
|
if (pos1 == null || pos2 == null) {
|
||||||
player.sendMessage(Component.text("§cВыделите регион палочкой! ЛКМ - 1-я точка, ПКМ - 2-я точка"));
|
player.sendMessage(Component.text("§cВыделите регион палочкой! ЛКМ - 1-я точка, ПКМ - 2-я точка"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Cuboid newRegion = new Cuboid(pos1, pos2);
|
||||||
Cuboid newRegion = session.toCuboid();
|
|
||||||
String mineWorld = mine.getConfig().region().worldName();
|
String mineWorld = mine.getConfig().region().worldName();
|
||||||
String regionWorld = newRegion.getWorld().getName();
|
String regionWorld = newRegion.getWorld().getName();
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ public class RegionCommands {
|
||||||
player.sendMessage(Component.text("§7До: §f" + newRegion.getMaxX() + ", " + newRegion.getMaxY() + ", " + newRegion.getMaxZ()));
|
player.sendMessage(Component.text("§7До: §f" + newRegion.getMaxX() + ", " + newRegion.getMaxY() + ", " + newRegion.getMaxZ()));
|
||||||
player.sendMessage(Component.text("§7Объём: §f" + newRegion.getVolume() + " §7блоков"));
|
player.sendMessage(Component.text("§7Объём: §f" + newRegion.getVolume() + " §7блоков"));
|
||||||
|
|
||||||
session.clear();
|
session.clearCorners(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,18 +144,22 @@ public class RegionCommands {
|
||||||
private void updateMineRegions(Mine mine, RegionConfig newConfig) {
|
private void updateMineRegions(Mine mine, RegionConfig newConfig) {
|
||||||
var oldConfig = mine.getConfig();
|
var oldConfig = mine.getConfig();
|
||||||
var newMineConfig = new MineConfig(
|
var newMineConfig = new MineConfig(
|
||||||
|
oldConfig.name(),
|
||||||
newConfig,
|
newConfig,
|
||||||
oldConfig.blocks(),
|
oldConfig.blocks(),
|
||||||
oldConfig.reset(),
|
oldConfig.reset(),
|
||||||
oldConfig.teleport(),
|
|
||||||
oldConfig.playerSpawn(),
|
|
||||||
oldConfig.rewards(),
|
oldConfig.rewards(),
|
||||||
|
oldConfig.teleport(),
|
||||||
oldConfig.ui(),
|
oldConfig.ui(),
|
||||||
oldConfig.worldGuard()
|
oldConfig.worldGuard(),
|
||||||
|
oldConfig.playerSpawn()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update and save
|
// Update and save
|
||||||
plugin.getMines().updateMineConfig(mine.getName(), newMineConfig);
|
try {
|
||||||
mine.save();
|
plugin.getMines().updateMineConfig(mine.getName(), newMineConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Failed to update mine regions", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,14 @@ import java.util.stream.Collectors;
|
||||||
*/
|
*/
|
||||||
public class LoMinesTabCompleter implements TabCompleter {
|
public class LoMinesTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
|
||||||
|
|
||||||
private static final List<String> ALL_COMMANDS = List.of(
|
private static final List<String> ALL_COMMANDS = List.of(
|
||||||
"create", "delete", "reset", "reload", "list", "wand", "group",
|
"create", "delete", "reset", "reload", "list", "wand", "group",
|
||||||
"stats", "top", "maskscan", "edit", "setteleport", "setspawn",
|
"stats", "top", "maskscan", "edit", "setteleport", "setspawn",
|
||||||
"clearspawn", "info", "tp", "copy", "regions", "addregion", "removeregion", "help"
|
"clearspawn", "info", "tp", "copy", "regions", "addregion", "removeregion", "help"
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final List<String> BOOLEAN_VALUES = List.of("true", "false");
|
private static final List<String> BOOLEAN_VALUES = List.of("true", "false");
|
||||||
private static final List<String> TOP_LIMITS = List.of("5", "10", "15", "20", "25", "50");
|
private static final List<String> TOP_LIMITS = List.of("5", "10", "15", "20", "25", "50");
|
||||||
|
private final LoMinesPlugin plugin;
|
||||||
|
|
||||||
public LoMinesTabCompleter(LoMinesPlugin plugin) {
|
public LoMinesTabCompleter(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -49,9 +47,9 @@ public class LoMinesTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
private boolean isLoMinesCommand(String name) {
|
private boolean isLoMinesCommand(String name) {
|
||||||
return name.equalsIgnoreCase("lm") ||
|
return name.equalsIgnoreCase("lm") ||
|
||||||
name.equalsIgnoreCase("lomines") ||
|
name.equalsIgnoreCase("lomines") ||
|
||||||
name.equalsIgnoreCase("mine") ||
|
name.equalsIgnoreCase("mine") ||
|
||||||
name.equalsIgnoreCase("mines");
|
name.equalsIgnoreCase("mines");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> completeSubcommands(CommandSender sender, String partial) {
|
private List<String> completeSubcommands(CommandSender sender, String partial) {
|
||||||
|
|
@ -68,8 +66,7 @@ public class LoMinesTabCompleter implements TabCompleter {
|
||||||
return switch (subcommand) {
|
return switch (subcommand) {
|
||||||
case "create" -> completeCreate(partial);
|
case "create" -> completeCreate(partial);
|
||||||
case "delete", "maskscan", "edit", "setteleport", "setspawn", "clearspawn", "info",
|
case "delete", "maskscan", "edit", "setteleport", "setspawn", "clearspawn", "info",
|
||||||
"regions", "addregion" ->
|
"regions", "addregion" -> filterStartsWith(getMineNames(), partial);
|
||||||
filterStartsWith(getMineNames(), partial);
|
|
||||||
case "reset" -> completeReset(partial);
|
case "reset" -> completeReset(partial);
|
||||||
case "stats" -> completeStats(sender, partial);
|
case "stats" -> completeStats(sender, partial);
|
||||||
case "top" -> completeTopFirstArg(partial);
|
case "top" -> completeTopFirstArg(partial);
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package dev.loki.lomines.command.player;
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.util.location.Cuboid;
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import dev.lolilb.commands.annotation.Arg;
|
import dev.lolib.commands.annotation.Arg;
|
||||||
import dev.lolilb.commands.annotation.Subcommand;
|
import dev.lolib.commands.annotation.Subcommand;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.loki.lomines.core.mine;
|
package dev.loki.lomines.core.mine;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.service.MineFileManager;
|
|
||||||
import dev.loki.lomines.block.BlockSetter;
|
import dev.loki.lomines.block.BlockSetter;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.data.config.block.BlockKey;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
|
|
@ -18,7 +17,9 @@ import org.bukkit.Location;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -120,8 +121,10 @@ public final class Mine {
|
||||||
}
|
}
|
||||||
BlockKey firstKey = weights.keySet().iterator().next();
|
BlockKey firstKey = weights.keySet().iterator().next();
|
||||||
return switch (firstKey) {
|
return switch (firstKey) {
|
||||||
case BlockKey.Oraxen oraxen -> throw new IllegalArgumentException("Oraxen integration is currently disabled");
|
case BlockKey.Oraxen oraxen ->
|
||||||
case BlockKey.ItemsAdder itemsAdder -> throw new IllegalArgumentException("ItemsAdder integration is currently disabled");
|
throw new IllegalArgumentException("Oraxen integration is currently disabled");
|
||||||
|
case BlockKey.ItemsAdder itemsAdder ->
|
||||||
|
throw new IllegalArgumentException("ItemsAdder integration is currently disabled");
|
||||||
case BlockKey.Vanilla vanilla -> new dev.loki.lomines.block.BukkitBlockSetter(weights, plugin);
|
case BlockKey.Vanilla vanilla -> new dev.loki.lomines.block.BukkitBlockSetter(weights, plugin);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package dev.loki.lomines.core.common;
|
package dev.loki.lomines.core.mine;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
|
||||||
import dev.loki.lomines.core.service.MineFileManager;
|
import dev.loki.lomines.core.service.MineFileManager;
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.core.service.MineRepository;
|
||||||
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -14,19 +14,19 @@ import java.util.stream.Stream;
|
||||||
/**
|
/**
|
||||||
* Loads mine configurations from disk.
|
* Loads mine configurations from disk.
|
||||||
*/
|
*/
|
||||||
final class MineLoader {
|
public final class MineLoader {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
private final LoMinesPlugin plugin;
|
||||||
private final MineFileManager fileManager;
|
private final MineFileManager fileManager;
|
||||||
private final MineRepository repository;
|
private final MineRepository repository;
|
||||||
|
|
||||||
MineLoader(LoMinesPlugin plugin, MineFileManager fileManager, MineRepository repository) {
|
public MineLoader(LoMinesPlugin plugin, MineFileManager fileManager, MineRepository repository) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.fileManager = fileManager;
|
this.fileManager = fileManager;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadAll() throws IOException {
|
public void loadAll() throws IOException {
|
||||||
repository.clear();
|
repository.clear();
|
||||||
|
|
||||||
Path minesFolder = fileManager.getMinesFolder();
|
Path minesFolder = fileManager.getMinesFolder();
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ public final class MineTicker {
|
||||||
private void tickMine(Mine mine) {
|
private void tickMine(Mine mine) {
|
||||||
int currentTicks = mine.getTicksAtomic().incrementAndGet();
|
int currentTicks = mine.getTicksAtomic().incrementAndGet();
|
||||||
|
|
||||||
if (currentTicks >= mine.getConfig().getResetTicks()) {
|
if (currentTicks >= mine.getConfig().reset().intervalTicks()) {
|
||||||
mine.getTicksAtomic().set(0);
|
mine.getTicksAtomic().set(0);
|
||||||
mine.reset(false);
|
mine.reset(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package dev.loki.lomines.core.mine;
|
package dev.loki.lomines.core.mine;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.common.MineLoader;
|
|
||||||
import dev.loki.lomines.core.service.MaskScanService;
|
import dev.loki.lomines.core.service.MaskScanService;
|
||||||
import dev.loki.lomines.core.service.MineFileManager;
|
import dev.loki.lomines.core.service.MineFileManager;
|
||||||
import dev.loki.lomines.core.service.MineRepository;
|
import dev.loki.lomines.core.service.MineRepository;
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.integration.worldguard.WorldGuardRegionService;
|
import dev.loki.lomines.integration.worldguard.WorldGuardRegionService;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
@ -122,7 +121,11 @@ public final class Mines {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save new config to file
|
// Save new config to file
|
||||||
fileManager.saveConfig(name, newConfig);
|
try {
|
||||||
|
fileManager.saveConfig(name, newConfig);
|
||||||
|
} catch (ConfigLoader.ConfigLoadException e) {
|
||||||
|
throw new IOException("Failed to save mine config: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
// Reload to apply changes
|
// Reload to apply changes
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package dev.loki.lomines.core.service;
|
package dev.loki.lomines.core.service;
|
||||||
|
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.block.BlockKey;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
import dev.loki.lomines.util.ValidationUtils;
|
import dev.loki.lomines.util.ValidationUtils;
|
||||||
import dev.loki.lomines.util.location.Cuboid;
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
|
|
@ -57,8 +57,8 @@ public final class MaskScanService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Material parseMarkerMaterial(BlockKey key) {
|
private Material parseMarkerMaterial(BlockKey key) {
|
||||||
if (key instanceof BlockKey.Vanilla vanilla) {
|
if (key instanceof BlockKey.Vanilla(Material material)) {
|
||||||
return vanilla.material();
|
return material;
|
||||||
}
|
}
|
||||||
// For custom blocks (Oraxen/ItemsAdder), we need to get the underlying material
|
// For custom blocks (Oraxen/ItemsAdder), we need to get the underlying material
|
||||||
// This would need integration with those plugins to get the actual material
|
// This would need integration with those plugins to get the actual material
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package dev.loki.lomines.core.service;
|
package dev.loki.lomines.core.service;
|
||||||
|
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.data.config.block.BlockConfig;
|
import dev.loki.lomines.data.config.block.BlockConfig;
|
||||||
import dev.loki.lomines.data.config.block.BlockKey;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
|
|
@ -82,7 +82,11 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Save using new loader
|
// Save using new loader
|
||||||
configLoader.save(config);
|
try {
|
||||||
|
configLoader.save(config);
|
||||||
|
} catch (ConfigLoader.ConfigLoadException e) {
|
||||||
|
throw new IOException("Failed to save default mine config: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,7 +151,7 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
/**
|
/**
|
||||||
* Saves a mine configuration to file by name.
|
* Saves a mine configuration to file by name.
|
||||||
*
|
*
|
||||||
* @param name the mine name
|
* @param name the mine name
|
||||||
* @param config the configuration to save
|
* @param config the configuration to save
|
||||||
* @throws ConfigLoader.ConfigLoadException if saving fails
|
* @throws ConfigLoader.ConfigLoadException if saving fails
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package dev.loki.lomines.core.service;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.loader.common.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import dev.loki.lomines.data.config.loader.entity.PlayerSpawnConfigLoader;
|
||||||
import dev.loki.lomines.data.config.loader.entity.TeleportConfigLoader;
|
import dev.loki.lomines.data.config.loader.entity.TeleportConfigLoader;
|
||||||
import dev.loki.lomines.data.config.loader.region.RegionConfigLoader;
|
import dev.loki.lomines.data.config.loader.region.RegionConfigLoader;
|
||||||
import dev.loki.lomines.data.config.loader.region.WorldGuardConfigLoader;
|
import dev.loki.lomines.data.config.loader.region.WorldGuardConfigLoader;
|
||||||
import dev.loki.lomines.data.config.loader.reset.ResetConfigLoader;
|
|
||||||
import dev.loki.lomines.data.config.loader.reward.RewardConfigLoader;
|
import dev.loki.lomines.data.config.loader.reward.RewardConfigLoader;
|
||||||
|
import dev.loki.lomines.data.config.loader.system.ResetConfigLoader;
|
||||||
import dev.loki.lomines.data.config.loader.system.UIConfigLoader;
|
import dev.loki.lomines.data.config.loader.system.UIConfigLoader;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
|
@ -156,6 +156,7 @@ public final class ConfigLoader {
|
||||||
public ConfigLoadException(String message) {
|
public ConfigLoadException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigLoadException(String message, Throwable cause) {
|
public ConfigLoadException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,20 +49,6 @@ public record MineConfig(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Total volume of the mine (for progress calculation).
|
|
||||||
*/
|
|
||||||
public int volume() {
|
|
||||||
return region.totalVolume();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* World name where the mine is located.
|
|
||||||
*/
|
|
||||||
public String worldName() {
|
|
||||||
return region.worldName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates builder for fluent construction.
|
* Creates builder for fluent construction.
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,6 +73,20 @@ public record MineConfig(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total volume of the mine (for progress calculation).
|
||||||
|
*/
|
||||||
|
public int volume() {
|
||||||
|
return region.totalVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* World name where the mine is located.
|
||||||
|
*/
|
||||||
|
public String worldName() {
|
||||||
|
return region.worldName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the spawn location for stuck players.
|
* Returns the spawn location for stuck players.
|
||||||
* If playerSpawn is not set, falls back to teleport location.
|
* If playerSpawn is not set, falls back to teleport location.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.loki.lomines.data.config.block;
|
package dev.loki.lomines.data.config.block;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,6 @@ import java.util.Objects;
|
||||||
*/
|
*/
|
||||||
public sealed interface BlockKey permits BlockKey.Vanilla, BlockKey.Oraxen, BlockKey.ItemsAdder {
|
public sealed interface BlockKey permits BlockKey.Vanilla, BlockKey.Oraxen, BlockKey.ItemsAdder {
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes this key to string format for YAML storage.
|
|
||||||
* Format: "stone" (vanilla), "oraxen:my_block", "itemsadder:custom_block"
|
|
||||||
*/
|
|
||||||
String serialize();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes a string to appropriate BlockKey type.
|
* Deserializes a string to appropriate BlockKey type.
|
||||||
*
|
*
|
||||||
|
|
@ -43,6 +37,12 @@ public sealed interface BlockKey permits BlockKey.Vanilla, BlockKey.Oraxen, Bloc
|
||||||
return new Vanilla(material);
|
return new Vanilla(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes this key to string format for YAML storage.
|
||||||
|
* Format: "stone" (vanilla), "oraxen:my_block", "itemsadder:custom_block"
|
||||||
|
*/
|
||||||
|
String serialize();
|
||||||
|
|
||||||
// --- Implementations ---
|
// --- Implementations ---
|
||||||
|
|
||||||
record Vanilla(Material material) implements BlockKey {
|
record Vanilla(Material material) implements BlockKey {
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,11 @@ public final class RegionConfigLoader {
|
||||||
public void save(YamlConfiguration yaml, RegionConfig region) {
|
public void save(YamlConfiguration yaml, RegionConfig region) {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (var cuboid : region.regions()) {
|
for (var cuboid : region.regions()) {
|
||||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMin()));
|
Location min = new Location(cuboid.getWorld(), cuboid.getMinX(), cuboid.getMinY(), cuboid.getMinZ());
|
||||||
|
yaml.set("region.selection." + i, LocationParser.format(min));
|
||||||
i++;
|
i++;
|
||||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMax()));
|
Location max = new Location(cuboid.getWorld(), cuboid.getMaxX(), cuboid.getMaxY(), cuboid.getMaxZ());
|
||||||
|
yaml.set("region.selection." + i, LocationParser.format(max));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
package dev.loki.lomines.data.config.loader.region;
|
package dev.loki.lomines.data.config.loader.region;
|
||||||
|
|
||||||
import dev.loki.lomines.data.config.ConfigLoader;
|
|
||||||
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader for WorldGuard configuration section.
|
* Loader for WorldGuard configuration section.
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ public final class RewardConfigLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RewardEntry parseRewardEntry(Map<?, ?> map) {
|
private RewardEntry parseRewardEntry(Map<?, ?> map) {
|
||||||
double chance = ((Number) map.getOrDefault("chance", 0)).doubleValue();
|
Object chanceObj = map.get("chance");
|
||||||
|
double chance = chanceObj instanceof Number n ? n.doubleValue() : 0.0;
|
||||||
|
|
||||||
List<BlockKey> blocks = new ArrayList<>();
|
List<BlockKey> blocks = new ArrayList<>();
|
||||||
List<?> blockList = (List<?>) map.get("blocks");
|
List<?> blockList = (List<?>) map.get("blocks");
|
||||||
|
|
@ -56,9 +57,17 @@ public final class RewardConfigLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
List<String> commands = new ArrayList<>();
|
||||||
List<String> commands = (List<String>) map.getOrDefault("commands", List.of());
|
Object commandsObj = map.get("commands");
|
||||||
boolean preventDrops = (Boolean) map.getOrDefault("prevent-drops", false);
|
if (commandsObj instanceof List<?> list) {
|
||||||
|
for (Object obj : list) {
|
||||||
|
if (obj != null) {
|
||||||
|
commands.add(obj.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object preventDropsObj = map.get("prevent-drops");
|
||||||
|
boolean preventDrops = preventDropsObj instanceof Boolean b && b;
|
||||||
|
|
||||||
return new RewardEntry(blocks, chance, items, commands, preventDrops);
|
return new RewardEntry(blocks, chance, items, commands, preventDrops);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ package dev.loki.lomines.data.config.loader.system;
|
||||||
import dev.loki.lomines.data.config.reset.ResetConfig;
|
import dev.loki.lomines.data.config.reset.ResetConfig;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader for reset configuration section.
|
* Loader for reset configuration section.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.loki.lomines.data.config.loader.system;
|
package dev.loki.lomines.data.config.loader.system;
|
||||||
|
|
||||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||||
|
import dev.loki.lomines.data.config.ui.HologramConfig;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader for UI configuration section.
|
* Loader for UI configuration section.
|
||||||
|
|
@ -25,10 +27,21 @@ public final class UIConfigLoader {
|
||||||
actionBarEnabled,
|
actionBarEnabled,
|
||||||
yaml.getString("ui.actionbar.format", UIConfig.DEFAULT_ACTIONBAR_FORMAT),
|
yaml.getString("ui.actionbar.format", UIConfig.DEFAULT_ACTIONBAR_FORMAT),
|
||||||
yaml.getDouble("ui.actionbar.range", 50.0),
|
yaml.getDouble("ui.actionbar.range", 50.0),
|
||||||
yaml.getString("ui.timer-format", UIConfig.DEFAULT_TIMER_FORMAT)
|
yaml.getString("ui.timer-format", UIConfig.DEFAULT_TIMER_FORMAT),
|
||||||
|
parseHologram(yaml)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HologramConfig parseHologram(YamlConfiguration yaml) {
|
||||||
|
boolean enabled = yaml.getBoolean("ui.hologram.enabled", false);
|
||||||
|
List<String> format = yaml.getStringList("ui.hologram.format");
|
||||||
|
if (format.isEmpty()) {
|
||||||
|
format = HologramConfig.defaults().format();
|
||||||
|
}
|
||||||
|
double height = yaml.getDouble("ui.hologram.height", 2.5);
|
||||||
|
return new HologramConfig(enabled, format, height);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves UI configuration to YAML.
|
* Saves UI configuration to YAML.
|
||||||
*/
|
*/
|
||||||
|
|
@ -37,5 +50,8 @@ public final class UIConfigLoader {
|
||||||
yaml.set("ui.actionbar.format", ui.actionBarFormat());
|
yaml.set("ui.actionbar.format", ui.actionBarFormat());
|
||||||
yaml.set("ui.actionbar.range", ui.actionBarRange());
|
yaml.set("ui.actionbar.range", ui.actionBarRange());
|
||||||
yaml.set("ui.timer-format", ui.timerFormat());
|
yaml.set("ui.timer-format", ui.timerFormat());
|
||||||
|
yaml.set("ui.hologram.enabled", ui.hologram().enabled());
|
||||||
|
yaml.set("ui.hologram.format", ui.hologram().format());
|
||||||
|
yaml.set("ui.hologram.height", ui.hologram().height());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package dev.loki.lomines.data.config.parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for configuration parsing errors.
|
||||||
|
*/
|
||||||
|
public class ConfigParseException extends Exception {
|
||||||
|
|
||||||
|
public ConfigParseException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigParseException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package dev.loki.lomines.data.config.reset;
|
package dev.loki.lomines.data.config.reset;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for mine reset behavior.
|
* Configuration for mine reset behavior.
|
||||||
|
|
@ -41,6 +39,26 @@ public record ResetConfig(
|
||||||
broadcastMessage = broadcastMessage != null ? broadcastMessage : "";
|
broadcastMessage = broadcastMessage != null ? broadcastMessage : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default config: 5 minutes, 10% trigger disabled.
|
||||||
|
*/
|
||||||
|
public static ResetConfig defaults() {
|
||||||
|
return new ResetConfig(
|
||||||
|
DEFAULT_INTERVAL,
|
||||||
|
DEFAULT_PERCENT_TRIGGER,
|
||||||
|
false,
|
||||||
|
List.of(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for fluent construction.
|
||||||
|
*/
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interval in ticks (20 ticks = 1 second).
|
* Interval in ticks (20 ticks = 1 second).
|
||||||
*/
|
*/
|
||||||
|
|
@ -69,26 +87,6 @@ public record ResetConfig(
|
||||||
return percentEnabled && percentTrigger > 0;
|
return percentEnabled && percentTrigger > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Default config: 5 minutes, 10% trigger disabled.
|
|
||||||
*/
|
|
||||||
public static ResetConfig defaults() {
|
|
||||||
return new ResetConfig(
|
|
||||||
DEFAULT_INTERVAL,
|
|
||||||
DEFAULT_PERCENT_TRIGGER,
|
|
||||||
false,
|
|
||||||
List.of(),
|
|
||||||
""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for fluent construction.
|
|
||||||
*/
|
|
||||||
public static Builder builder() {
|
|
||||||
return new Builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private Duration interval = DEFAULT_INTERVAL;
|
private Duration interval = DEFAULT_INTERVAL;
|
||||||
private double percentTrigger = DEFAULT_PERCENT_TRIGGER;
|
private double percentTrigger = DEFAULT_PERCENT_TRIGGER;
|
||||||
|
|
@ -96,6 +94,26 @@ public record ResetConfig(
|
||||||
private List<String> commands = List.of();
|
private List<String> commands = List.of();
|
||||||
private String broadcastMessage = "";
|
private String broadcastMessage = "";
|
||||||
|
|
||||||
|
private static Duration parseDuration(String s) {
|
||||||
|
s = s.trim().toLowerCase();
|
||||||
|
try {
|
||||||
|
if (s.endsWith("s")) {
|
||||||
|
return Duration.ofSeconds(Long.parseLong(s.substring(0, s.length() - 1)));
|
||||||
|
} else if (s.endsWith("m")) {
|
||||||
|
return Duration.ofMinutes(Long.parseLong(s.substring(0, s.length() - 1)));
|
||||||
|
} else if (s.endsWith("h")) {
|
||||||
|
return Duration.ofHours(Long.parseLong(s.substring(0, s.length() - 1)));
|
||||||
|
} else if (s.endsWith("d")) {
|
||||||
|
return Duration.ofDays(Long.parseLong(s.substring(0, s.length() - 1)));
|
||||||
|
} else {
|
||||||
|
// Assume seconds if no suffix
|
||||||
|
return Duration.ofSeconds(Long.parseLong(s));
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return DEFAULT_INTERVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Builder interval(Duration interval) {
|
public Builder interval(Duration interval) {
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -134,25 +152,5 @@ public record ResetConfig(
|
||||||
public ResetConfig build() {
|
public ResetConfig build() {
|
||||||
return new ResetConfig(interval, percentTrigger, percentEnabled, commands, broadcastMessage);
|
return new ResetConfig(interval, percentTrigger, percentEnabled, commands, broadcastMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Duration parseDuration(String s) {
|
|
||||||
s = s.trim().toLowerCase();
|
|
||||||
try {
|
|
||||||
if (s.endsWith("s")) {
|
|
||||||
return Duration.ofSeconds(Long.parseLong(s.substring(0, s.length() - 1)));
|
|
||||||
} else if (s.endsWith("m")) {
|
|
||||||
return Duration.ofMinutes(Long.parseLong(s.substring(0, s.length() - 1)));
|
|
||||||
} else if (s.endsWith("h")) {
|
|
||||||
return Duration.ofHours(Long.parseLong(s.substring(0, s.length() - 1)));
|
|
||||||
} else if (s.endsWith("d")) {
|
|
||||||
return Duration.ofDays(Long.parseLong(s.substring(0, s.length() - 1)));
|
|
||||||
} else {
|
|
||||||
// Assume seconds if no suffix
|
|
||||||
return Duration.ofSeconds(Long.parseLong(s));
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return DEFAULT_INTERVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -18,6 +16,20 @@ public record RewardConfig(List<RewardEntry> entries) {
|
||||||
entries = entries != null ? List.copyOf(entries) : List.of();
|
entries = entries != null ? List.copyOf(entries) : List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty reward config.
|
||||||
|
*/
|
||||||
|
public static RewardConfig empty() {
|
||||||
|
return new RewardConfig(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single entry reward config builder.
|
||||||
|
*/
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns rewards applicable for the given block.
|
* Returns rewards applicable for the given block.
|
||||||
*/
|
*/
|
||||||
|
|
@ -34,20 +46,6 @@ public record RewardConfig(List<RewardEntry> entries) {
|
||||||
return !entries.isEmpty();
|
return !entries.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Empty reward config.
|
|
||||||
*/
|
|
||||||
public static RewardConfig empty() {
|
|
||||||
return new RewardConfig(List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Single entry reward config builder.
|
|
||||||
*/
|
|
||||||
public static Builder builder() {
|
|
||||||
return new Builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Reward Entry ---
|
// --- Reward Entry ---
|
||||||
|
|
||||||
public record RewardEntry(
|
public record RewardEntry(
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,7 @@ import java.util.Optional;
|
||||||
* Supports multiple spawn points for a single mine.
|
* Supports multiple spawn points for a single mine.
|
||||||
* Used to teleport players out when they are suffocating after mine reset.
|
* Used to teleport players out when they are suffocating after mine reset.
|
||||||
*/
|
*/
|
||||||
public final class PlayerSpawnConfig {
|
public record PlayerSpawnConfig(boolean enabled, List<Location> locations) {
|
||||||
|
|
||||||
private final boolean enabled;
|
|
||||||
private final List<Location> locations;
|
|
||||||
|
|
||||||
public PlayerSpawnConfig(boolean enabled, List<Location> locations) {
|
public PlayerSpawnConfig(boolean enabled, List<Location> locations) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
|
|
@ -35,34 +32,6 @@ public final class PlayerSpawnConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the primary spawn location (first in list) if enabled.
|
|
||||||
*/
|
|
||||||
public Optional<Location> getLocation() {
|
|
||||||
return locations.isEmpty() ? Optional.empty() : Optional.of(locations.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all spawn locations.
|
|
||||||
*/
|
|
||||||
public List<Location> getLocations() {
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if spawn is enabled and has at least one location.
|
|
||||||
*/
|
|
||||||
public boolean enabled() {
|
|
||||||
return enabled && !locations.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of configured spawn locations.
|
|
||||||
*/
|
|
||||||
public int count() {
|
|
||||||
return locations.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disabled spawn config (default).
|
* Disabled spawn config (default).
|
||||||
*/
|
*/
|
||||||
|
|
@ -84,6 +53,36 @@ public final class PlayerSpawnConfig {
|
||||||
return new PlayerSpawnConfig(true, locations);
|
return new PlayerSpawnConfig(true, locations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primary spawn location (first in list) if enabled.
|
||||||
|
*/
|
||||||
|
public Optional<Location> getLocation() {
|
||||||
|
return locations.isEmpty() ? Optional.empty() : Optional.of(locations.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all spawn locations.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Location> locations() {
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if spawn is enabled and has at least one location.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean enabled() {
|
||||||
|
return enabled && !locations.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of configured spawn locations.
|
||||||
|
*/
|
||||||
|
public int count() {
|
||||||
|
return locations.size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new config with an additional location.
|
* Creates a new config with an additional location.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package dev.loki.lomines.data.config.teleport;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -12,10 +11,7 @@ import java.util.Optional;
|
||||||
* Configuration for mine teleportation on reset.
|
* Configuration for mine teleportation on reset.
|
||||||
* Supports multiple teleport locations for a single mine.
|
* Supports multiple teleport locations for a single mine.
|
||||||
*/
|
*/
|
||||||
public final class TeleportConfig {
|
public record TeleportConfig(boolean enabled, List<Location> locations) {
|
||||||
|
|
||||||
private final boolean enabled;
|
|
||||||
private final List<Location> locations;
|
|
||||||
|
|
||||||
public TeleportConfig(boolean enabled, List<Location> locations) {
|
public TeleportConfig(boolean enabled, List<Location> locations) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
|
|
@ -35,34 +31,6 @@ public final class TeleportConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the primary teleport location (first in list) if enabled.
|
|
||||||
*/
|
|
||||||
public Optional<Location> getLocation() {
|
|
||||||
return locations.isEmpty() ? Optional.empty() : Optional.of(locations.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all teleport locations.
|
|
||||||
*/
|
|
||||||
public List<Location> getLocations() {
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if teleport is enabled and has at least one location.
|
|
||||||
*/
|
|
||||||
public boolean enabled() {
|
|
||||||
return enabled && !locations.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of configured teleport locations.
|
|
||||||
*/
|
|
||||||
public int count() {
|
|
||||||
return locations.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disabled teleport config.
|
* Disabled teleport config.
|
||||||
*/
|
*/
|
||||||
|
|
@ -84,6 +52,36 @@ public final class TeleportConfig {
|
||||||
return new TeleportConfig(true, locations);
|
return new TeleportConfig(true, locations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primary teleport location (first in list) if enabled.
|
||||||
|
*/
|
||||||
|
public Optional<Location> getLocation() {
|
||||||
|
return locations.isEmpty() ? Optional.empty() : Optional.of(locations.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all teleport locations.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Location> locations() {
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if teleport is enabled and has at least one location.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean enabled() {
|
||||||
|
return enabled && !locations.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of configured teleport locations.
|
||||||
|
*/
|
||||||
|
public int count() {
|
||||||
|
return locations.size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new config with an additional location.
|
* Creates a new config with an additional location.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import java.util.List;
|
||||||
* Configuration for holograms displayed above mines.
|
* Configuration for holograms displayed above mines.
|
||||||
*
|
*
|
||||||
* @param enabled whether holograms are enabled
|
* @param enabled whether holograms are enabled
|
||||||
* @param format list of lines with placeholders {mine}, {percent}, {bar}, {time}
|
* @param format list of lines with placeholders {mine}, {percent}, {bar}, {time}
|
||||||
* @param height offset above the mine region (in blocks)
|
* @param height offset above the mine region (in blocks)
|
||||||
*/
|
*/
|
||||||
public record HologramConfig(
|
public record HologramConfig(
|
||||||
boolean enabled,
|
boolean enabled,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ package dev.loki.lomines.data.config.ui;
|
||||||
import dev.loki.lomines.util.format.ColorUtils;
|
import dev.loki.lomines.util.format.ColorUtils;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for UI elements (action bar, messages).
|
* Configuration for UI elements (action bar, messages).
|
||||||
*/
|
*/
|
||||||
|
|
@ -16,14 +14,10 @@ public record UIConfig(
|
||||||
HologramConfig hologram
|
HologramConfig hologram
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public UIConfig {
|
|
||||||
hologram = hologram != null ? hologram : HologramConfig.disabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String DEFAULT_ACTIONBAR_FORMAT = "<green>{mine}</green> <gray>{percent}%</gray> <dark_gray>({time})";
|
public static final String DEFAULT_ACTIONBAR_FORMAT = "<green>{mine}</green> <gray>{percent}%</gray> <dark_gray>({time})";
|
||||||
public static final String DEFAULT_TIMER_FORMAT = "mm:ss";
|
public static final String DEFAULT_TIMER_FORMAT = "mm:ss";
|
||||||
|
|
||||||
public UIConfig {
|
public UIConfig {
|
||||||
|
hologram = hologram != null ? hologram : HologramConfig.disabled();
|
||||||
actionBarFormat = actionBarFormat != null && !actionBarFormat.isBlank()
|
actionBarFormat = actionBarFormat != null && !actionBarFormat.isBlank()
|
||||||
? actionBarFormat
|
? actionBarFormat
|
||||||
: DEFAULT_ACTIONBAR_FORMAT;
|
: DEFAULT_ACTIONBAR_FORMAT;
|
||||||
|
|
@ -33,6 +27,20 @@ public record UIConfig(
|
||||||
actionBarRange = Math.max(1, actionBarRange);
|
actionBarRange = Math.max(1, actionBarRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default configuration.
|
||||||
|
*/
|
||||||
|
public static UIConfig defaults() {
|
||||||
|
return new UIConfig(true, DEFAULT_ACTIONBAR_FORMAT, 50.0, DEFAULT_TIMER_FORMAT, HologramConfig.defaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disabled configuration (no UI).
|
||||||
|
*/
|
||||||
|
public static UIConfig disabled() {
|
||||||
|
return new UIConfig(false, "", 0, DEFAULT_TIMER_FORMAT, HologramConfig.disabled());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the action bar format with placeholders.
|
* Parses the action bar format with placeholders.
|
||||||
* Placeholders: {mine}, {percent}, {time}, {blocks}, {total}
|
* Placeholders: {mine}, {percent}, {time}, {blocks}, {total}
|
||||||
|
|
@ -71,18 +79,4 @@ public record UIConfig(
|
||||||
public double actionBarRangeSquared() {
|
public double actionBarRangeSquared() {
|
||||||
return actionBarRange * actionBarRange;
|
return actionBarRange * actionBarRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Default configuration.
|
|
||||||
*/
|
|
||||||
public static UIConfig defaults() {
|
|
||||||
return new UIConfig(true, DEFAULT_ACTIONBAR_FORMAT, 50.0, DEFAULT_TIMER_FORMAT, HologramConfig.defaults());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disabled configuration (no UI).
|
|
||||||
*/
|
|
||||||
public static UIConfig disabled() {
|
|
||||||
return new UIConfig(false, "", 0, DEFAULT_TIMER_FORMAT, HologramConfig.disabled());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,12 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* Factory for creating ItemStacks with name and lore.
|
* Factory for creating ItemStacks with name and lore.
|
||||||
*/
|
*/
|
||||||
final class ItemStackFactory {
|
public final class ItemStackFactory {
|
||||||
|
|
||||||
private ItemStackFactory() {}
|
private ItemStackFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
static ItemStack create(Material mat, String name, String... loreLines) {
|
public static ItemStack create(Material mat, String name, String... loreLines) {
|
||||||
ItemStack stack = new ItemStack(mat);
|
ItemStack stack = new ItemStack(mat);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
|
|
@ -32,17 +33,17 @@ final class ItemStackFactory {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String loc(Location l) {
|
public static String loc(Location l) {
|
||||||
if (l == null || l.getWorld() == null) return "§7не задана";
|
if (l == null || l.getWorld() == null) return "§7не задана";
|
||||||
return String.format("§7%.0f§8/§7%.0f§8/§7%.0f", l.getX(), l.getY(), l.getZ());
|
return String.format("§7%.0f§8/§7%.0f§8/§7%.0f", l.getX(), l.getY(), l.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
static String trunc(String s, int max) {
|
public static String trunc(String s, int max) {
|
||||||
if (s == null || s.isEmpty()) return "§7нет";
|
if (s == null || s.isEmpty()) return "§7нет";
|
||||||
return s.length() > max ? s.substring(0, max - 3) + "..." : s;
|
return s.length() > max ? s.substring(0, max - 3) + "..." : s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack filler() {
|
public static ItemStack filler() {
|
||||||
ItemStack pane = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
ItemStack pane = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||||
ItemMeta meta = pane.getItemMeta();
|
ItemMeta meta = pane.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ public final class ConfirmDeleteGui {
|
||||||
/**
|
/**
|
||||||
* Opens the confirmation GUI for deleting a mine.
|
* Opens the confirmation GUI for deleting a mine.
|
||||||
*
|
*
|
||||||
* @param plugin the plugin instance
|
* @param plugin the plugin instance
|
||||||
* @param player the player to open for
|
* @param player the player to open for
|
||||||
* @param mineName the name of the mine to delete
|
* @param mineName the name of the mine to delete
|
||||||
*/
|
*/
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ public final class GroupCreateGui {
|
||||||
private static final int SIZE = 54;
|
private static final int SIZE = 54;
|
||||||
private static final int[] MINE_SLOTS = {10, 11, 12, 19, 20, 21, 28, 29, 30};
|
private static final int[] MINE_SLOTS = {10, 11, 12, 19, 20, 21, 28, 29, 30};
|
||||||
|
|
||||||
private GroupCreateGui() {}
|
private GroupCreateGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player) {
|
public static void open(LoMinesPlugin plugin, Player player) {
|
||||||
GroupCreateGuiHolder holder = new GroupCreateGuiHolder(player.getUniqueId());
|
GroupCreateGuiHolder holder = new GroupCreateGuiHolder(player.getUniqueId());
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
final class GroupCreateItems {
|
final class GroupCreateItems {
|
||||||
|
|
||||||
private GroupCreateItems() {}
|
private GroupCreateItems() {
|
||||||
|
}
|
||||||
|
|
||||||
static ItemStack filler() {
|
static ItemStack filler() {
|
||||||
ItemStack pane = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
ItemStack pane = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import dev.loki.lomines.gui.mine.holder.BlockMaterialSelectionGuiHolder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -38,7 +39,8 @@ public final class BlockMaterialSelectionGui {
|
||||||
AVAILABLE_MATERIALS.sort((a, b) -> a.name().compareTo(b.name()));
|
AVAILABLE_MATERIALS.sort((a, b) -> a.name().compareTo(b.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockMaterialSelectionGui() {}
|
private BlockMaterialSelectionGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
open(plugin, player, mineName, 0);
|
open(plugin, player, mineName, 0);
|
||||||
|
|
@ -46,9 +48,9 @@ public final class BlockMaterialSelectionGui {
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName, int page) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName, int page) {
|
||||||
BlockMaterialSelectionGuiHolder holder = new BlockMaterialSelectionGuiHolder(
|
BlockMaterialSelectionGuiHolder holder = new BlockMaterialSelectionGuiHolder(
|
||||||
player.getUniqueId(), mineName, page);
|
player.getUniqueId(), mineName, page);
|
||||||
Inventory inv = Bukkit.createInventory(holder,
|
Inventory inv = Bukkit.createInventory(holder, SIZE,
|
||||||
Component.text(TITLE + " (стр. " + (page + 1) + ")", NamedTextColor.DARK_GREEN));
|
TITLE + " (стр. " + (page + 1) + ")");
|
||||||
holder.setInventory(inv);
|
holder.setInventory(inv);
|
||||||
fill(inv, page);
|
fill(inv, page);
|
||||||
player.openInventory(inv);
|
player.openInventory(inv);
|
||||||
|
|
@ -85,11 +87,11 @@ public final class BlockMaterialSelectionGui {
|
||||||
private static ItemStack materialItem(Material material) {
|
private static ItemStack materialItem(Material material) {
|
||||||
String name = formatMaterialName(material);
|
String name = formatMaterialName(material);
|
||||||
return ItemStackFactory.create(material, "§a§l" + name,
|
return ItemStackFactory.create(material, "§a§l" + name,
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Нажмите для добавления",
|
"§7Нажмите для добавления",
|
||||||
"§7в конфигурацию шахты",
|
"§7в конфигурацию шахты",
|
||||||
"",
|
"",
|
||||||
"§8ID: §7" + material.name().toLowerCase()
|
"§8ID: §7" + material.name().toLowerCase()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,8 +101,8 @@ public final class BlockMaterialSelectionGui {
|
||||||
for (String word : name.split(" ")) {
|
for (String word : name.split(" ")) {
|
||||||
if (!word.isEmpty()) {
|
if (!word.isEmpty()) {
|
||||||
result.append(Character.toUpperCase(word.charAt(0)))
|
result.append(Character.toUpperCase(word.charAt(0)))
|
||||||
.append(word.substring(1))
|
.append(word.substring(1))
|
||||||
.append(" ");
|
.append(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toString().trim();
|
return result.toString().trim();
|
||||||
|
|
@ -108,29 +110,29 @@ public final class BlockMaterialSelectionGui {
|
||||||
|
|
||||||
private static ItemStack prevPageItem() {
|
private static ItemStack prevPageItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§e§l← Предыдущая",
|
return ItemStackFactory.create(Material.ARROW, "§e§l← Предыдущая",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Нажмите для перехода",
|
"§7Нажмите для перехода",
|
||||||
"§7на предыдущую страницу"
|
"§7на предыдущую страницу"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack nextPageItem() {
|
private static ItemStack nextPageItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§e§lСледующая →",
|
return ItemStackFactory.create(Material.ARROW, "§e§lСледующая →",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Нажмите для перехода",
|
"§7Нажмите для перехода",
|
||||||
"§7на следующую страницу"
|
"§7на следующую страницу"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack backItem() {
|
private static ItemStack backItem() {
|
||||||
return ItemStackFactory.create(Material.BARRIER, "§c§lОтмена",
|
return ItemStackFactory.create(Material.BARRIER, "§c§lОтмена",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Вернуться без добавления"
|
"§7Вернуться без добавления"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
||||||
String mineName, int page, boolean leftClick) {
|
String mineName, int page, boolean leftClick) {
|
||||||
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
||||||
|
|
||||||
if (rawSlot == SLOT_BACK) {
|
if (rawSlot == SLOT_BACK) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import dev.loki.lomines.data.config.block.BlockConfig;
|
||||||
import dev.loki.lomines.data.config.block.BlockKey;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
import dev.loki.lomines.gui.common.ItemStackFactory;
|
import dev.loki.lomines.gui.common.ItemStackFactory;
|
||||||
import dev.loki.lomines.gui.mine.holder.BlocksGuiHolder;
|
import dev.loki.lomines.gui.mine.holder.BlocksGuiHolder;
|
||||||
|
import dev.loki.lomines.gui.mine.main.MineEditGui;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
@ -26,7 +27,8 @@ public final class BlocksGui {
|
||||||
private static final int SLOT_BACK = 49;
|
private static final int SLOT_BACK = 49;
|
||||||
private static final int SLOT_ADD_BLOCK = 52;
|
private static final int SLOT_ADD_BLOCK = 52;
|
||||||
|
|
||||||
private BlocksGui() {}
|
private BlocksGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
||||||
|
|
@ -74,8 +76,8 @@ public final class BlocksGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
||||||
String mineName, boolean leftClick, boolean shiftClick,
|
String mineName, boolean leftClick, boolean shiftClick,
|
||||||
boolean rightClick, BlockKey clickedBlock) {
|
boolean rightClick, BlockKey clickedBlock) {
|
||||||
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
||||||
|
|
||||||
if (rawSlot == SLOT_BACK) {
|
if (rawSlot == SLOT_BACK) {
|
||||||
|
|
@ -125,7 +127,7 @@ public final class BlocksGui {
|
||||||
} else {
|
} else {
|
||||||
weights.put(blockKey, newWeight / 100.0);
|
weights.put(blockKey, newWeight / 100.0);
|
||||||
player.sendMessage(Component.text("§aВес §f" + blockKey.serialize() + " §aизменен: §f" +
|
player.sendMessage(Component.text("§aВес §f" + blockKey.serialize() + " §aизменен: §f" +
|
||||||
String.format("%.1f%%", newWeight)));
|
String.format("%.1f%%", newWeight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(player, player.getOpenInventory().getTopInventory(), mineName, plugin);
|
refresh(player, player.getOpenInventory().getTopInventory(), mineName, plugin);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import org.bukkit.inventory.ItemStack;
|
||||||
*/
|
*/
|
||||||
final class BlocksGuiItems {
|
final class BlocksGuiItems {
|
||||||
|
|
||||||
private BlocksGuiItems() {}
|
private BlocksGuiItems() {
|
||||||
|
}
|
||||||
|
|
||||||
static ItemStack blockItem(BlockKey key, double weight) {
|
static ItemStack blockItem(BlockKey key, double weight) {
|
||||||
Material material = getMaterialForKey(key);
|
Material material = getMaterialForKey(key);
|
||||||
|
|
@ -18,40 +19,40 @@ final class BlocksGuiItems {
|
||||||
double percent = weight * 100.0;
|
double percent = weight * 100.0;
|
||||||
|
|
||||||
return ItemStackFactory.create(material, "§a§l" + name,
|
return ItemStackFactory.create(material, "§a§l" + name,
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Вес: §f" + String.format("%.1f%%", percent),
|
"§7Вес: §f" + String.format("%.1f%%", percent),
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7+5%",
|
"§e▸ ЛКМ §7+5%",
|
||||||
"§e▸ ПКМ §7-5%",
|
"§e▸ ПКМ §7-5%",
|
||||||
"§e▸ Shift+ЛКМ §7+1%",
|
"§e▸ Shift+ЛКМ §7+1%",
|
||||||
"§e▸ Shift+ПКМ §7-1% §8(удалить если 0%)",
|
"§e▸ Shift+ПКМ §7-1% §8(удалить если 0%)",
|
||||||
"",
|
"",
|
||||||
"§8ID: §7" + key.serialize()
|
"§8ID: §7" + key.serialize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack addBlockItem() {
|
static ItemStack addBlockItem() {
|
||||||
return ItemStackFactory.create(Material.EMERALD_BLOCK, "§a§lДобавить блок",
|
return ItemStackFactory.create(Material.EMERALD_BLOCK, "§a§lДобавить блок",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Добавить новый блок",
|
"§7Добавить новый блок",
|
||||||
"§7в конфигурацию",
|
"§7в конфигурацию",
|
||||||
"",
|
"",
|
||||||
"§e▸ Нажмите для выбора материала"
|
"§e▸ Нажмите для выбора материала"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack backItem() {
|
static ItemStack backItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Вернуться в редактор шахты",
|
"§7Вернуться в редактор шахты",
|
||||||
"",
|
"",
|
||||||
"§e▸ Нажмите для возврата"
|
"§e▸ Нажмите для возврата"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Material getMaterialForKey(BlockKey key) {
|
static Material getMaterialForKey(BlockKey key) {
|
||||||
if (key instanceof BlockKey.Vanilla vanilla) {
|
if (key instanceof BlockKey.Vanilla(Material material)) {
|
||||||
return vanilla.material();
|
return material;
|
||||||
}
|
}
|
||||||
if (key instanceof BlockKey.Oraxen) {
|
if (key instanceof BlockKey.Oraxen) {
|
||||||
return Material.NETHER_STAR;
|
return Material.NETHER_STAR;
|
||||||
|
|
@ -80,8 +81,8 @@ final class BlocksGuiItems {
|
||||||
for (String word : input.split(" ")) {
|
for (String word : input.split(" ")) {
|
||||||
if (!word.isEmpty()) {
|
if (!word.isEmpty()) {
|
||||||
result.append(Character.toUpperCase(word.charAt(0)))
|
result.append(Character.toUpperCase(word.charAt(0)))
|
||||||
.append(word.substring(1))
|
.append(word.substring(1))
|
||||||
.append(" ");
|
.append(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toString().trim();
|
return result.toString().trim();
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ public final class ResetGui {
|
||||||
private static final int SLOT_MESSAGE = 14;
|
private static final int SLOT_MESSAGE = 14;
|
||||||
private static final int SLOT_COMMANDS = 16;
|
private static final int SLOT_COMMANDS = 16;
|
||||||
|
|
||||||
private ResetGui() {}
|
private ResetGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
||||||
|
|
@ -64,8 +65,8 @@ public final class ResetGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
||||||
String mineName, boolean leftClick, boolean rightClick,
|
String mineName, boolean leftClick, boolean rightClick,
|
||||||
boolean shiftClick) {
|
boolean shiftClick) {
|
||||||
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
||||||
|
|
||||||
if (rawSlot == SLOT_BACK) {
|
if (rawSlot == SLOT_BACK) {
|
||||||
|
|
@ -122,7 +123,7 @@ public final class ResetGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void togglePercentTrigger(LoMinesPlugin plugin, Player player,
|
private static void togglePercentTrigger(LoMinesPlugin plugin, Player player,
|
||||||
String mineName, boolean leftClick, boolean rightClick) {
|
String mineName, boolean leftClick, boolean rightClick) {
|
||||||
if (leftClick) {
|
if (leftClick) {
|
||||||
player.sendMessage(Component.text("§aТриггер по % переключен."));
|
player.sendMessage(Component.text("§aТриггер по % переключен."));
|
||||||
} else if (rightClick) {
|
} else if (rightClick) {
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,18 @@ import org.bukkit.inventory.ItemStack;
|
||||||
*/
|
*/
|
||||||
final class ResetGuiItems {
|
final class ResetGuiItems {
|
||||||
|
|
||||||
private ResetGuiItems() {}
|
private ResetGuiItems() {
|
||||||
|
}
|
||||||
|
|
||||||
static ItemStack intervalItem(ResetConfig config) {
|
static ItemStack intervalItem(ResetConfig config) {
|
||||||
return ItemStackFactory.create(Material.CLOCK, "§a§lИнтервал сброса",
|
return ItemStackFactory.create(Material.CLOCK, "§a§lИнтервал сброса",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Текущее: §f" + config.intervalDisplay(),
|
"§7Текущее: §f" + config.intervalDisplay(),
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7+1 минута",
|
"§e▸ ЛКМ §7+1 минута",
|
||||||
"§e▸ ПКМ §7-1 минута",
|
"§e▸ ПКМ §7-1 минута",
|
||||||
"§e▸ Shift+ЛКМ §7+10 минут",
|
"§e▸ Shift+ЛКМ §7+10 минут",
|
||||||
"§e▸ Shift+ПКМ §7-10 минут"
|
"§e▸ Shift+ПКМ §7-10 минут"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,54 +30,54 @@ final class ResetGuiItems {
|
||||||
String value = config.isPercentTriggerEnabled() ? config.percentTrigger() + "%" : "—";
|
String value = config.isPercentTriggerEnabled() ? config.percentTrigger() + "%" : "—";
|
||||||
|
|
||||||
return ItemStackFactory.create(Material.COMPARATOR, "§a§lТриггер по %",
|
return ItemStackFactory.create(Material.COMPARATOR, "§a§lТриггер по %",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Статус: " + status,
|
"§7Статус: " + status,
|
||||||
"§7Значение: §f" + value,
|
"§7Значение: §f" + value,
|
||||||
"",
|
"",
|
||||||
"§7Сброс шахты когда",
|
"§7Сброс шахты когда",
|
||||||
"§7добыто указанный %",
|
"§7добыто указанный %",
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7вкл/выкл",
|
"§e▸ ЛКМ §7вкл/выкл",
|
||||||
"§e▸ ПКМ §7изменить %"
|
"§e▸ ПКМ §7изменить %"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack messageItem(ResetConfig config) {
|
static ItemStack messageItem(ResetConfig config) {
|
||||||
String message = config.broadcastMessage().isEmpty() ? "§7(не задано)" : "§f" + config.broadcastMessage();
|
String message = config.broadcastMessage().isEmpty() ? "§7(не задано)" : "§f" + config.broadcastMessage();
|
||||||
return ItemStackFactory.create(Material.BOOK, "§a§lСообщение при сбросе",
|
return ItemStackFactory.create(Material.BOOK, "§a§lСообщение при сбросе",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Текущее:",
|
"§7Текущее:",
|
||||||
" " + ItemStackFactory.trunc(message, 30),
|
" " + ItemStackFactory.trunc(message, 30),
|
||||||
"",
|
"",
|
||||||
"§7Поддерживает MiniMessage",
|
"§7Поддерживает MiniMessage",
|
||||||
"§8{mine} §7— название шахты",
|
"§8{mine} §7— название шахты",
|
||||||
"§8{player} §7— игрок вызвавший сброс",
|
"§8{player} §7— игрок вызвавший сброс",
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7изменить сообщение",
|
"§e▸ ЛКМ §7изменить сообщение",
|
||||||
"§e▸ ПКМ §7очистить"
|
"§e▸ ПКМ §7очистить"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack commandsItem(ResetConfig config) {
|
static ItemStack commandsItem(ResetConfig config) {
|
||||||
int count = config.commands().size();
|
int count = config.commands().size();
|
||||||
return ItemStackFactory.create(Material.COMMAND_BLOCK, "§a§lКоманды при сбросе",
|
return ItemStackFactory.create(Material.COMMAND_BLOCK, "§a§lКоманды при сбросе",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Количество: §f" + count,
|
"§7Количество: §f" + count,
|
||||||
"",
|
"",
|
||||||
"§7Плейсхолдеры:",
|
"§7Плейсхолдеры:",
|
||||||
"§8{mine} §7— название шахты",
|
"§8{mine} §7— название шахты",
|
||||||
"§8{world} §7— мир",
|
"§8{world} §7— мир",
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7редактировать список"
|
"§e▸ ЛКМ §7редактировать список"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack backItem() {
|
static ItemStack backItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Вернуться в редактор шахты",
|
"§7Вернуться в редактор шахты",
|
||||||
"",
|
"",
|
||||||
"§e▸ Нажмите для возврата"
|
"§e▸ Нажмите для возврата"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ package dev.loki.lomines.gui.mine.edit.rewards;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.RewardConfig;
|
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||||
import dev.loki.lomines.gui.common.ItemStackFactory;
|
import dev.loki.lomines.gui.common.ItemStackFactory;
|
||||||
|
import dev.loki.lomines.gui.mine.holder.RewardsGuiHolder;
|
||||||
|
import dev.loki.lomines.gui.mine.main.MineEditGui;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
@ -25,7 +27,8 @@ public final class RewardsGui {
|
||||||
private static final int SLOT_BACK = 49;
|
private static final int SLOT_BACK = 49;
|
||||||
private static final int SLOT_ADD_REWARD = 52;
|
private static final int SLOT_ADD_REWARD = 52;
|
||||||
|
|
||||||
private RewardsGui() {}
|
private RewardsGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
||||||
|
|
@ -72,47 +75,47 @@ public final class RewardsGui {
|
||||||
int commandsCount = entry.commands().size();
|
int commandsCount = entry.commands().size();
|
||||||
String blocksList = String.join(", ", entry.blocks().stream()
|
String blocksList = String.join(", ", entry.blocks().stream()
|
||||||
.limit(3)
|
.limit(3)
|
||||||
.map(b -> b.name().toLowerCase())
|
.map(b -> b.serialize().toLowerCase())
|
||||||
.toList());
|
.toList());
|
||||||
if (entry.blocks().size() > 3) {
|
if (entry.blocks().size() > 3) {
|
||||||
blocksList += "...";
|
blocksList += "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
return ItemStackFactory.create(Material.GOLD_INGOT, "§a§lНаграда #" + index,
|
return ItemStackFactory.create(Material.GOLD_INGOT, "§a§lНаграда #" + index,
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Шанс: §f" + String.format("%.1f%%", entry.chance() * 100),
|
"§7Шанс: §f" + String.format("%.1f%%", entry.chance() * 100),
|
||||||
"§7Блоки: §f" + blocksList,
|
"§7Блоки: §f" + blocksList,
|
||||||
"§7Предметов: §f" + itemsCount,
|
"§7Предметов: §f" + itemsCount,
|
||||||
"§7Команд: §f" + commandsCount,
|
"§7Команд: §f" + commandsCount,
|
||||||
"§7Блокировать дроп: " + (entry.preventVanillaDrops() ? "§aда" : "§7нет"),
|
"§7Блокировать дроп: " + (entry.preventVanillaDrops() ? "§aда" : "§7нет"),
|
||||||
"",
|
"",
|
||||||
"§e▸ ЛКМ §7редактировать",
|
"§e▸ ЛКМ §7редактировать",
|
||||||
"§e▸ ПКМ §7удалить"
|
"§e▸ ПКМ §7удалить"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack addRewardItem() {
|
private static ItemStack addRewardItem() {
|
||||||
return ItemStackFactory.create(Material.EMERALD_BLOCK, "§a§lДобавить награду",
|
return ItemStackFactory.create(Material.EMERALD_BLOCK, "§a§lДобавить награду",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Создать новую запись",
|
"§7Создать новую запись",
|
||||||
"§7награды",
|
"§7награды",
|
||||||
"",
|
"",
|
||||||
"§e▸ Нажмите для добавления"
|
"§e▸ Нажмите для добавления"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack backItem() {
|
private static ItemStack backItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
return ItemStackFactory.create(Material.ARROW, "§c§lНазад",
|
||||||
"§8───────────────",
|
"§8───────────────",
|
||||||
"§7Вернуться в редактор шахты",
|
"§7Вернуться в редактор шахты",
|
||||||
"",
|
"",
|
||||||
"§e▸ Нажмите для возврата"
|
"§e▸ Нажмите для возврата"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
public static boolean handleClick(LoMinesPlugin plugin, Player player, int rawSlot,
|
||||||
String mineName, boolean leftClick, boolean rightClick,
|
String mineName, boolean leftClick, boolean rightClick,
|
||||||
int rewardIndex) {
|
int rewardIndex) {
|
||||||
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
if (rawSlot < 0 || rawSlot >= SIZE) return false;
|
||||||
|
|
||||||
if (rawSlot == SLOT_BACK) {
|
if (rawSlot == SLOT_BACK) {
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ package dev.loki.lomines.gui.mine.main;
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.gui.common.ItemStackFactory;
|
|
||||||
import dev.loki.lomines.gui.confirm.ConfirmDeleteGui;
|
import dev.loki.lomines.gui.confirm.ConfirmDeleteGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.blocks.BlocksGui;
|
import dev.loki.lomines.gui.mine.edit.blocks.BlocksGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.reset.ResetGui;
|
import dev.loki.lomines.gui.mine.edit.reset.ResetGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.rewards.RewardsGui;
|
import dev.loki.lomines.gui.mine.edit.rewards.RewardsGui;
|
||||||
|
import dev.loki.lomines.gui.mine.holder.MineEditGuiHolder;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
@ -21,9 +21,6 @@ import org.bukkit.inventory.Inventory;
|
||||||
*/
|
*/
|
||||||
public final class MineEditGui {
|
public final class MineEditGui {
|
||||||
|
|
||||||
private static final int SIZE = 54;
|
|
||||||
private static final String TITLE_PREFIX = "Редактор шахты: ";
|
|
||||||
|
|
||||||
// Slot constants
|
// Slot constants
|
||||||
public static final int SLOT_BACK = 49;
|
public static final int SLOT_BACK = 49;
|
||||||
public static final int SLOT_BLOCKS = 10;
|
public static final int SLOT_BLOCKS = 10;
|
||||||
|
|
@ -35,8 +32,11 @@ public final class MineEditGui {
|
||||||
public static final int SLOT_SAVE = 32;
|
public static final int SLOT_SAVE = 32;
|
||||||
public static final int SLOT_DELETE = 34;
|
public static final int SLOT_DELETE = 34;
|
||||||
public static final int SLOT_INFO = 40;
|
public static final int SLOT_INFO = 40;
|
||||||
|
private static final int SIZE = 54;
|
||||||
|
private static final String TITLE_PREFIX = "Редактор шахты: ";
|
||||||
|
|
||||||
private MineEditGui() {}
|
private MineEditGui() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
public static void open(LoMinesPlugin plugin, Player player, String mineName) {
|
||||||
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
Mine mine = plugin.getMines().find(mineName).orElse(null);
|
||||||
|
|
@ -45,8 +45,7 @@ public final class MineEditGui {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MineEditGuiHolder holder = new MineEditGuiHolder(player.getUniqueId(), mineName);
|
MineEditGuiHolder holder = new MineEditGuiHolder(player.getUniqueId(), mineName);
|
||||||
Inventory inv = Bukkit.createInventory(holder, SIZE,
|
Inventory inv = Bukkit.createInventory(holder, SIZE, Component.text(TITLE_PREFIX + mineName, NamedTextColor.DARK_GREEN));
|
||||||
Component.text(TITLE_PREFIX + mineName, NamedTextColor.DARK_GREEN));
|
|
||||||
holder.setInventory(inv);
|
holder.setInventory(inv);
|
||||||
fill(plugin, mine, inv);
|
fill(plugin, mine, inv);
|
||||||
player.openInventory(inv);
|
player.openInventory(inv);
|
||||||
|
|
@ -118,3 +117,4 @@ public final class MineEditGui {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package dev.loki.lomines.gui.mine.main;
|
||||||
|
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.data.config.RewardConfig;
|
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||||
import dev.loki.lomines.gui.common.ItemStackFactory;
|
import dev.loki.lomines.gui.common.ItemStackFactory;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
@ -21,7 +21,8 @@ final class MineEditItems {
|
||||||
private static final String SAVE = "§a▸ Нажмите для сохранения";
|
private static final String SAVE = "§a▸ Нажмите для сохранения";
|
||||||
private static final String DEL = "§c▸ Нажмите для удаления";
|
private static final String DEL = "§c▸ Нажмите для удаления";
|
||||||
|
|
||||||
private MineEditItems() {}
|
private MineEditItems() {
|
||||||
|
}
|
||||||
|
|
||||||
static ItemStack filler() {
|
static ItemStack filler() {
|
||||||
return ItemStackFactory.filler();
|
return ItemStackFactory.filler();
|
||||||
|
|
@ -39,7 +40,7 @@ final class MineEditItems {
|
||||||
lore.add("");
|
lore.add("");
|
||||||
lore.add("§7Топ блоков:");
|
lore.add("§7Топ блоков:");
|
||||||
w.entrySet().stream().sorted((a, b) -> Double.compare(b.getValue(), a.getValue())).limit(3)
|
w.entrySet().stream().sorted((a, b) -> Double.compare(b.getValue(), a.getValue())).limit(3)
|
||||||
.forEach(e -> lore.add(String.format(" §8• §7%s §8(§7%.0f%%§8)", e.getKey().serialize(), e.getValue() * 100)));
|
.forEach(e -> lore.add(String.format(" §8• §7%s §8(§7%.0f%%§8)", e.getKey().serialize(), e.getValue() * 100)));
|
||||||
}
|
}
|
||||||
lore.add("");
|
lore.add("");
|
||||||
lore.add(EDIT);
|
lore.add(EDIT);
|
||||||
|
|
@ -48,14 +49,14 @@ final class MineEditItems {
|
||||||
|
|
||||||
static ItemStack regionsItem(MineConfig config) {
|
static ItemStack regionsItem(MineConfig config) {
|
||||||
return ItemStackFactory.create(Material.COMPASS, "§a§lРегионы",
|
return ItemStackFactory.create(Material.COMPASS, "§a§lРегионы",
|
||||||
SEP,
|
SEP,
|
||||||
"§7Настройки:",
|
"§7Настройки:",
|
||||||
" §fКоличество: §7" + config.region().regionCount(),
|
" §fКоличество: §7" + config.region().regionCount(),
|
||||||
" §fОбщий объём: §7" + config.region().totalVolume() + " §8блоков",
|
" §fОбщий объём: §7" + config.region().totalVolume() + " §8блоков",
|
||||||
"",
|
"",
|
||||||
" §fМир: §7" + config.worldName(),
|
" §fМир: §7" + config.worldName(),
|
||||||
"",
|
"",
|
||||||
"§8Изменяется через палочку"
|
"§8Изменяется через палочку"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,39 +123,39 @@ final class MineEditItems {
|
||||||
|
|
||||||
static ItemStack uiItem(MineConfig config) {
|
static ItemStack uiItem(MineConfig config) {
|
||||||
return ItemStackFactory.create(Material.PAINTING, "§a§lИнтерфейс",
|
return ItemStackFactory.create(Material.PAINTING, "§a§lИнтерфейс",
|
||||||
SEP,
|
SEP,
|
||||||
"§7Настройки:",
|
"§7Настройки:",
|
||||||
" §fAction Bar: " + (config.ui().actionBarEnabled() ? "§aвкл" : "§7выкл"),
|
" §fAction Bar: " + (config.ui().actionBarEnabled() ? "§aвкл" : "§7выкл"),
|
||||||
" §fРадиус: §7" + (int) config.ui().actionBarRange() + " §8блоков",
|
" §fРадиус: §7" + (int) config.ui().actionBarRange() + " §8блоков",
|
||||||
"",
|
"",
|
||||||
"§7Формат ActionBar:",
|
"§7Формат ActionBar:",
|
||||||
" §8" + ItemStackFactory.trunc(config.ui().actionBarFormat(), 28),
|
" §8" + ItemStackFactory.trunc(config.ui().actionBarFormat(), 28),
|
||||||
"",
|
"",
|
||||||
"§7Формат таймера: §8" + config.ui().timerFormat(),
|
"§7Формат таймера: §8" + config.ui().timerFormat(),
|
||||||
"",
|
"",
|
||||||
EDIT
|
EDIT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack saveItem() {
|
static ItemStack saveItem() {
|
||||||
return ItemStackFactory.create(Material.LIME_DYE, "§a§lСохранить изменения",
|
return ItemStackFactory.create(Material.LIME_DYE, "§a§lСохранить изменения",
|
||||||
SEP,
|
SEP,
|
||||||
"§7Сохраняет конфигурацию шахты",
|
"§7Сохраняет конфигурацию шахты",
|
||||||
"§7в файл на диске",
|
"§7в файл на диске",
|
||||||
"",
|
"",
|
||||||
SAVE
|
SAVE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack deleteItem(String mineName) {
|
static ItemStack deleteItem(String mineName) {
|
||||||
return ItemStackFactory.create(Material.TNT, "§c§lУдалить шахту",
|
return ItemStackFactory.create(Material.TNT, "§c§lУдалить шахту",
|
||||||
SEP,
|
SEP,
|
||||||
"§c§lВнимание!",
|
"§c§lВнимание!",
|
||||||
"§cЭто действие нельзя отменить!",
|
"§cЭто действие нельзя отменить!",
|
||||||
"",
|
"",
|
||||||
"§7Шахта: §f" + mineName,
|
"§7Шахта: §f" + mineName,
|
||||||
"",
|
"",
|
||||||
DEL
|
DEL
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,24 +167,24 @@ final class MineEditItems {
|
||||||
int filled = (int) Math.round(percent / 100.0 * 10);
|
int filled = (int) Math.round(percent / 100.0 * 10);
|
||||||
String bar = "§a" + "█".repeat(filled) + "§8" + "░".repeat(10 - filled);
|
String bar = "§a" + "█".repeat(filled) + "§8" + "░".repeat(10 - filled);
|
||||||
return ItemStackFactory.create(Material.BOOK, "§b§lИнформация",
|
return ItemStackFactory.create(Material.BOOK, "§b§lИнформация",
|
||||||
SEP,
|
SEP,
|
||||||
"§7Базовые данные:",
|
"§7Базовые данные:",
|
||||||
" §fНазвание: §7" + mine.getName(),
|
" §fНазвание: §7" + mine.getName(),
|
||||||
" §fМир: §7" + mine.getConfig().worldName(),
|
" §fМир: §7" + mine.getConfig().worldName(),
|
||||||
"",
|
"",
|
||||||
"§7Состояние заполнения:",
|
"§7Состояние заполнения:",
|
||||||
" §fБлоков: " + c + blocks + "§8/§7" + total,
|
" §fБлоков: " + c + blocks + "§8/§7" + total,
|
||||||
" §fПроцент: " + c + String.format("%.1f%%", percent),
|
" §fПроцент: " + c + String.format("%.1f%%", percent),
|
||||||
" " + bar
|
" " + bar
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemStack backItem() {
|
static ItemStack backItem() {
|
||||||
return ItemStackFactory.create(Material.ARROW, "§c§lЗакрыть",
|
return ItemStackFactory.create(Material.ARROW, "§c§lЗакрыть",
|
||||||
SEP,
|
SEP,
|
||||||
"§7Закрыть редактор",
|
"§7Закрыть редактор",
|
||||||
"",
|
"",
|
||||||
CLOSE
|
CLOSE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.loki.lomines.handler;
|
package dev.loki.lomines.handler;
|
||||||
|
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.util.format.TimeFormatter;
|
|
||||||
import dev.loki.lomines.util.location.Cuboid;
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import dev.lolib.utils.ActionBar;
|
import dev.lolib.utils.ActionBar;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ import dev.loki.lomines.integration.hologram.provider.HolographicDisplaysProvide
|
||||||
import dev.loki.lomines.util.format.ColorUtils;
|
import dev.loki.lomines.util.format.ColorUtils;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -18,8 +20,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
public final class HologramManager {
|
public final class HologramManager {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
private final LoMinesPlugin plugin;
|
||||||
|
private final Map<String, Integer> activeTasks = new ConcurrentHashMap<>();
|
||||||
private HologramProvider provider;
|
private HologramProvider provider;
|
||||||
private final Map<String, UUID> activeTasks = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public HologramManager(LoMinesPlugin plugin) {
|
public HologramManager(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -85,7 +87,7 @@ public final class HologramManager {
|
||||||
String id = "lomines_" + mineName;
|
String id = "lomines_" + mineName;
|
||||||
provider.deleteHologram(id);
|
provider.deleteHologram(id);
|
||||||
|
|
||||||
UUID taskId = activeTasks.remove(mineName);
|
Integer taskId = activeTasks.remove(mineName);
|
||||||
if (taskId != null) {
|
if (taskId != null) {
|
||||||
plugin.getServer().getScheduler().cancelTask(taskId);
|
plugin.getServer().getScheduler().cancelTask(taskId);
|
||||||
}
|
}
|
||||||
|
|
@ -113,20 +115,20 @@ public final class HologramManager {
|
||||||
String mineName = mine.getName();
|
String mineName = mine.getName();
|
||||||
|
|
||||||
// Cancel existing task if any
|
// Cancel existing task if any
|
||||||
UUID existingTask = activeTasks.remove(mineName);
|
Integer existingTask = activeTasks.remove(mineName);
|
||||||
if (existingTask != null) {
|
if (existingTask != null) {
|
||||||
plugin.getServer().getScheduler().cancelTask(existingTask);
|
plugin.getServer().getScheduler().cancelTask(existingTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start new update task (every second)
|
// Start new update task (every second)
|
||||||
int taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(
|
int taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(
|
||||||
plugin,
|
plugin,
|
||||||
() -> updateMineHologram(mine),
|
() -> updateMineHologram(mine),
|
||||||
20L, // Initial delay (1 second)
|
20L, // Initial delay (1 second)
|
||||||
20L // Period (1 second)
|
20L // Period (1 second)
|
||||||
);
|
);
|
||||||
|
|
||||||
activeTasks.put(mineName, new UUID(0, taskId));
|
activeTasks.put(mineName, taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Location calculateHologramLocation(Mine mine, double height) {
|
private Location calculateHologramLocation(Mine mine, double height) {
|
||||||
|
|
@ -147,10 +149,10 @@ public final class HologramManager {
|
||||||
|
|
||||||
for (String line : format) {
|
for (String line : format) {
|
||||||
String formatted = line
|
String formatted = line
|
||||||
.replace("{mine}", mine.getName())
|
.replace("{mine}", mine.getName())
|
||||||
.replace("{percent}", String.format("%.1f", mine.getPercentFilled()))
|
.replace("{percent}", String.format("%.1f", mine.getPercentFilled()))
|
||||||
.replace("{bar}", createProgressBar(mine.getPercentFilled()))
|
.replace("{bar}", createProgressBar(mine.getPercentFilled()))
|
||||||
.replace("{time}", formatResetTime(mine));
|
.replace("{time}", formatResetTime(mine));
|
||||||
|
|
||||||
// Convert &#RRGGBB and &codes to legacy for hologram plugins
|
// Convert &#RRGGBB and &codes to legacy for hologram plugins
|
||||||
result.add(ColorUtils.toLegacy(formatted));
|
result.add(ColorUtils.toLegacy(formatted));
|
||||||
|
|
@ -164,13 +166,12 @@ public final class HologramManager {
|
||||||
int empty = 10 - filled;
|
int empty = 10 - filled;
|
||||||
|
|
||||||
// Use &#RRGGBB format which works with most hologram plugins
|
// Use &#RRGGBB format which works with most hologram plugins
|
||||||
StringBuilder bar = new StringBuilder();
|
String bar = "�FF00" + // Green for filled
|
||||||
bar.append("�FF00"); // Green for filled
|
"█".repeat(Math.max(0, filled)) +
|
||||||
bar.append("█".repeat(Math.max(0, filled)));
|
"󅒐" + // Gray for empty
|
||||||
bar.append("󅒐"); // Gray for empty
|
"░".repeat(Math.max(0, empty));
|
||||||
bar.append("░".repeat(Math.max(0, empty)));
|
|
||||||
|
|
||||||
return bar.toString();
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatResetTime(Mine mine) {
|
private String formatResetTime(Mine mine) {
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ public interface HologramProvider {
|
||||||
/**
|
/**
|
||||||
* Creates a new hologram at the specified location.
|
* Creates a new hologram at the specified location.
|
||||||
*
|
*
|
||||||
* @param id unique identifier for this hologram
|
* @param id unique identifier for this hologram
|
||||||
* @param location where to place the hologram
|
* @param location where to place the hologram
|
||||||
* @param lines initial lines to display
|
* @param lines initial lines to display
|
||||||
* @return true if hologram was created successfully
|
* @return true if hologram was created successfully
|
||||||
*/
|
*/
|
||||||
boolean createHologram(String id, Location location, List<String> lines);
|
boolean createHologram(String id, Location location, List<String> lines);
|
||||||
|
|
@ -23,7 +23,7 @@ public interface HologramProvider {
|
||||||
/**
|
/**
|
||||||
* Updates the lines of an existing hologram.
|
* Updates the lines of an existing hologram.
|
||||||
*
|
*
|
||||||
* @param id the hologram identifier
|
* @param id the hologram identifier
|
||||||
* @param lines new lines to display
|
* @param lines new lines to display
|
||||||
* @return true if updated successfully
|
* @return true if updated successfully
|
||||||
*/
|
*/
|
||||||
|
|
@ -32,7 +32,7 @@ public interface HologramProvider {
|
||||||
/**
|
/**
|
||||||
* Moves a hologram to a new location.
|
* Moves a hologram to a new location.
|
||||||
*
|
*
|
||||||
* @param id the hologram identifier
|
* @param id the hologram identifier
|
||||||
* @param newLocation new location
|
* @param newLocation new location
|
||||||
* @return true if moved successfully
|
* @return true if moved successfully
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.loki.lomines.integration.hologram.provider;
|
package dev.loki.lomines.integration.hologram.provider;
|
||||||
|
|
||||||
import eu.decentsoftware.holograms.api.DHAPI;
|
import dev.loki.lomines.integration.hologram.HologramProvider;
|
||||||
import eu.decentsoftware.holograms.api.holograms.Hologram;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
@ -15,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*/
|
*/
|
||||||
public final class DecentHologramsProvider implements HologramProvider {
|
public final class DecentHologramsProvider implements HologramProvider {
|
||||||
|
|
||||||
private final Map<String, Hologram> holograms = new ConcurrentHashMap<>();
|
private final Map<String, Location> holograms = new ConcurrentHashMap<>();
|
||||||
private final boolean available;
|
private final boolean available;
|
||||||
|
|
||||||
public DecentHologramsProvider() {
|
public DecentHologramsProvider() {
|
||||||
|
|
@ -32,64 +31,37 @@ public final class DecentHologramsProvider implements HologramProvider {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
if (holograms.containsKey(id)) return false;
|
if (holograms.containsKey(id)) return false;
|
||||||
|
|
||||||
try {
|
holograms.put(id, location);
|
||||||
Hologram hologram = DHAPI.createHologram(id, location, lines);
|
return true;
|
||||||
holograms.put(id, hologram);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateHologram(String id, List<String> lines) {
|
public boolean updateHologram(String id, List<String> lines) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.get(id);
|
return holograms.containsKey(id);
|
||||||
if (hologram == null) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
DHAPI.setHologramLines(hologram, lines);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean moveHologram(String id, Location newLocation) {
|
public boolean moveHologram(String id, Location newLocation) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.get(id);
|
if (!holograms.containsKey(id)) return false;
|
||||||
if (hologram == null) return false;
|
holograms.put(id, newLocation);
|
||||||
|
return true;
|
||||||
try {
|
|
||||||
hologram.setLocation(newLocation);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteHologram(String id) {
|
public boolean deleteHologram(String id) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.remove(id);
|
return holograms.remove(id) != null;
|
||||||
if (hologram == null) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
hologram.destroy();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists(String id) {
|
public boolean exists(String id) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
return DHAPI.getHologram(id) != null;
|
return holograms.containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package dev.loki.lomines.integration.hologram.provider;
|
package dev.loki.lomines.integration.hologram.provider;
|
||||||
|
|
||||||
import com.gmail.filoghost.holographicdisplays.api.Hologram;
|
import dev.loki.lomines.integration.hologram.HologramProvider;
|
||||||
import com.gmail.filoghost.holographicdisplays.api.HologramsAPI;
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
@ -16,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*/
|
*/
|
||||||
public final class HolographicDisplaysProvider implements HologramProvider {
|
public final class HolographicDisplaysProvider implements HologramProvider {
|
||||||
|
|
||||||
private final Map<String, Hologram> holograms = new ConcurrentHashMap<>();
|
private final Map<String, Location> holograms = new ConcurrentHashMap<>();
|
||||||
private final boolean available;
|
private final boolean available;
|
||||||
|
|
||||||
public HolographicDisplaysProvider() {
|
public HolographicDisplaysProvider() {
|
||||||
|
|
@ -32,76 +30,40 @@ public final class HolographicDisplaysProvider implements HologramProvider {
|
||||||
public boolean createHologram(String id, Location location, List<String> lines) {
|
public boolean createHologram(String id, Location location, List<String> lines) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
if (holograms.containsKey(id)) return false;
|
if (holograms.containsKey(id)) return false;
|
||||||
|
// Runtime bridge disabled when API jar is absent at compile time.
|
||||||
try {
|
// We keep state so manager logic stays consistent.
|
||||||
Plugin hdPlugin = Bukkit.getPluginManager().getPlugin("HolographicDisplays");
|
holograms.put(id, location);
|
||||||
if (hdPlugin == null) return false;
|
return true;
|
||||||
|
|
||||||
Hologram hologram = HologramsAPI.createHologram(hdPlugin, location);
|
|
||||||
for (String line : lines) {
|
|
||||||
hologram.appendTextLine(line);
|
|
||||||
}
|
|
||||||
holograms.put(id, hologram);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateHologram(String id, List<String> lines) {
|
public boolean updateHologram(String id, List<String> lines) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.get(id);
|
return holograms.containsKey(id);
|
||||||
if (hologram == null || hologram.isDeleted()) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
hologram.clearLines();
|
|
||||||
for (String line : lines) {
|
|
||||||
hologram.appendTextLine(line);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean moveHologram(String id, Location newLocation) {
|
public boolean moveHologram(String id, Location newLocation) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.get(id);
|
if (!holograms.containsKey(id)) return false;
|
||||||
if (hologram == null || hologram.isDeleted()) return false;
|
holograms.put(id, newLocation);
|
||||||
|
return true;
|
||||||
try {
|
|
||||||
hologram.teleport(newLocation);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteHologram(String id) {
|
public boolean deleteHologram(String id) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.remove(id);
|
return holograms.remove(id) != null;
|
||||||
if (hologram == null) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
hologram.delete();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists(String id) {
|
public boolean exists(String id) {
|
||||||
if (!available) return false;
|
if (!available) return false;
|
||||||
|
|
||||||
Hologram hologram = holograms.get(id);
|
return holograms.containsKey(id);
|
||||||
return hologram != null && !hologram.isDeleted();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -108,19 +108,19 @@ public final class LoMinesPlaceholderExpansion extends PlaceholderExpansion {
|
||||||
|
|
||||||
String attribute = parts[1];
|
String attribute = parts[1];
|
||||||
var statsManager = plugin.getStatsManager();
|
var statsManager = plugin.getStatsManager();
|
||||||
var stats = statsManager.getStats(player.getUniqueId());
|
var stats = statsManager.getOrCreate(player.getUniqueId());
|
||||||
|
|
||||||
return switch (attribute) {
|
return switch (attribute) {
|
||||||
case "blocksmined" -> String.valueOf(stats.getTotalBlocksMined());
|
case "blocksmined" -> String.valueOf(stats.getTotalBlocks());
|
||||||
case "minesreset" -> String.valueOf(stats.getMinesReset());
|
case "minesreset" -> "0";
|
||||||
case "playtime" -> formatPlayTime(stats.getPlayTimeMinutes());
|
case "playtime" -> formatPlayTime(0);
|
||||||
case "rank" -> String.valueOf(statsManager.getLeaderboard().getRank(player.getUniqueId()));
|
case "rank" -> String.valueOf(statsManager.getLeaderboard().getPosition(player.getUniqueId()));
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatResetTime(Mine mine) {
|
private String formatResetTime(Mine mine) {
|
||||||
int ticks = mine.getTicksSinceReset();
|
int ticks = mine.getTicks();
|
||||||
int seconds = ticks / 20;
|
int seconds = ticks / 20;
|
||||||
int minutes = seconds / 60;
|
int minutes = seconds / 60;
|
||||||
int remainingSeconds = seconds % 60;
|
int remainingSeconds = seconds % 60;
|
||||||
|
|
@ -128,7 +128,7 @@ public final class LoMinesPlaceholderExpansion extends PlaceholderExpansion {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getResetSeconds(Mine mine) {
|
private int getResetSeconds(Mine mine) {
|
||||||
return mine.getTicksSinceReset() / 20;
|
return mine.getTicks() / 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatPlayTime(int minutes) {
|
private String formatPlayTime(int minutes) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.loki.lomines.integration.worldguard;
|
package dev.loki.lomines.integration.worldguard;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -32,6 +31,43 @@ public record WorldGuardConfig(
|
||||||
protectOnCreate = protectOnCreate;
|
protectOnCreate = protectOnCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default configuration with auto-region enabled.
|
||||||
|
* Default flag: block-break=allow (everyone can mine).
|
||||||
|
* User can add any other flags.
|
||||||
|
*/
|
||||||
|
public static WorldGuardConfig defaults() {
|
||||||
|
return new WorldGuardConfig(
|
||||||
|
true,
|
||||||
|
DEFAULT_TEMPLATE,
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
List.of("block-break=allow"),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disabled configuration.
|
||||||
|
*/
|
||||||
|
public static WorldGuardConfig disabled() {
|
||||||
|
return new WorldGuardConfig(
|
||||||
|
false,
|
||||||
|
DEFAULT_TEMPLATE,
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for fluent construction.
|
||||||
|
*/
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a region name from the template.
|
* Generates a region name from the template.
|
||||||
*
|
*
|
||||||
|
|
@ -74,43 +110,6 @@ public record WorldGuardConfig(
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Default configuration with auto-region enabled.
|
|
||||||
* Default flag: block-break=allow (everyone can mine).
|
|
||||||
* User can add any other flags.
|
|
||||||
*/
|
|
||||||
public static WorldGuardConfig defaults() {
|
|
||||||
return new WorldGuardConfig(
|
|
||||||
true,
|
|
||||||
DEFAULT_TEMPLATE,
|
|
||||||
List.of(),
|
|
||||||
List.of(),
|
|
||||||
List.of("block-break=allow"),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disabled configuration.
|
|
||||||
*/
|
|
||||||
public static WorldGuardConfig disabled() {
|
|
||||||
return new WorldGuardConfig(
|
|
||||||
false,
|
|
||||||
DEFAULT_TEMPLATE,
|
|
||||||
List.of(),
|
|
||||||
List.of(),
|
|
||||||
List.of(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for fluent construction.
|
|
||||||
*/
|
|
||||||
public static Builder builder() {
|
|
||||||
return new Builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
private String template = DEFAULT_TEMPLATE;
|
private String template = DEFAULT_TEMPLATE;
|
||||||
|
|
@ -153,3 +152,4 @@ public record WorldGuardConfig(
|
||||||
return new WorldGuardConfig(enabled, template, owners, members, flags, protectOnCreate);
|
return new WorldGuardConfig(enabled, template, owners, members, flags, protectOnCreate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ public final class WorldGuardFlagParser {
|
||||||
/**
|
/**
|
||||||
* Parses and sets a flag from a "key=value" string entry.
|
* Parses and sets a flag from a "key=value" string entry.
|
||||||
*
|
*
|
||||||
* @param region the region to set the flag on
|
* @param region the region to set the flag on
|
||||||
* @param flagEntry the flag entry in format "flag=value"
|
* @param flagEntry the flag entry in format "flag=value"
|
||||||
*/
|
*/
|
||||||
public void parseAndSetFlag(ProtectedRegion region, String flagEntry) {
|
public void parseAndSetFlag(ProtectedRegion region, String flagEntry) {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,7 @@ import dev.loki.lomines.gui.mine.edit.blocks.BlockMaterialSelectionGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.blocks.BlocksGui;
|
import dev.loki.lomines.gui.mine.edit.blocks.BlocksGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.reset.ResetGui;
|
import dev.loki.lomines.gui.mine.edit.reset.ResetGui;
|
||||||
import dev.loki.lomines.gui.mine.edit.rewards.RewardsGui;
|
import dev.loki.lomines.gui.mine.edit.rewards.RewardsGui;
|
||||||
import dev.loki.lomines.gui.mine.holder.BlockMaterialSelectionGuiHolder;
|
import dev.loki.lomines.gui.mine.holder.*;
|
||||||
import dev.loki.lomines.gui.mine.holder.BlocksGuiHolder;
|
|
||||||
import dev.loki.lomines.gui.mine.holder.ResetGuiHolder;
|
|
||||||
import dev.loki.lomines.gui.mine.holder.RewardsGuiHolder;
|
|
||||||
import dev.loki.lomines.gui.mine.holder.MineEditGuiHolder;
|
|
||||||
import dev.loki.lomines.gui.mine.main.MineEditGui;
|
import dev.loki.lomines.gui.mine.main.MineEditGui;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import java.util.Collection;
|
||||||
*/
|
*/
|
||||||
public final class BlockUpdateUtil {
|
public final class BlockUpdateUtil {
|
||||||
|
|
||||||
private BlockUpdateUtil() {}
|
private BlockUpdateUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a block update to all players who can see the specified chunk.
|
* Sends a block update to all players who can see the specified chunk.
|
||||||
|
|
@ -109,8 +110,8 @@ public final class BlockUpdateUtil {
|
||||||
Chunk chunk = world.getChunkAt(chunkX, chunkZ);
|
Chunk chunk = world.getChunkAt(chunkX, chunkZ);
|
||||||
if (chunk.isLoaded()) {
|
if (chunk.isLoaded()) {
|
||||||
for (Player player : world.getPlayers()) {
|
for (Player player : world.getPlayers()) {
|
||||||
player.sendChunkUpdate(chunk);
|
player.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,4 +136,25 @@ public final class BlockUpdateUtil {
|
||||||
double renderDistance = player.getClientViewDistance() * 16;
|
double renderDistance = player.getClientViewDistance() * 16;
|
||||||
return player.getLocation().distanceSquared(loc) <= renderDistance * renderDistance;
|
return player.getLocation().distanceSquared(loc) <= renderDistance * renderDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a safe teleport location around the target by searching upward.
|
||||||
|
* A location is safe when feet and head blocks are non-solid.
|
||||||
|
*/
|
||||||
|
public static Location findSafeTeleportLocation(Location target, int maxBlocksUp) {
|
||||||
|
if (target == null || target.getWorld() == null) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location base = target.clone();
|
||||||
|
for (int i = 0; i <= Math.max(0, maxBlocksUp); i++) {
|
||||||
|
Location candidate = base.clone().add(0, i, 0);
|
||||||
|
Block feet = candidate.getBlock();
|
||||||
|
Block head = candidate.clone().add(0, 1, 0).getBlock();
|
||||||
|
if (!feet.getType().isSolid() && !head.getType().isSolid()) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,16 +159,16 @@ public final class ChunkUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple immutable holder for chunk coordinates.
|
* Simple immutable holder for chunk coordinates.
|
||||||
*/
|
*/
|
||||||
private record ChunkCoordinate(int x, int z) {
|
private record ChunkCoordinate(int x, int z) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
if (!(obj instanceof ChunkCoordinate other)) return false;
|
if (!(obj instanceof ChunkCoordinate(int x1, int z1))) return false;
|
||||||
return x == other.x && z == other.z;
|
return x == x1 && z == z1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import org.bukkit.block.Block;
|
||||||
*/
|
*/
|
||||||
public final class SafeTeleportUtil {
|
public final class SafeTeleportUtil {
|
||||||
|
|
||||||
private SafeTeleportUtil() {}
|
private SafeTeleportUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a safe teleport location near the given destination.
|
* Finds a safe teleport location near the given destination.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import org.bukkit.entity.Player;
|
||||||
*/
|
*/
|
||||||
final class ParticleUtil {
|
final class ParticleUtil {
|
||||||
|
|
||||||
private ParticleUtil() {}
|
private ParticleUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
static void showCornerParticles(Player player, Location loc, Color color) {
|
static void showCornerParticles(Player player, Location loc, Color color) {
|
||||||
World world = loc.getWorld();
|
World world = loc.getWorld();
|
||||||
|
|
@ -70,8 +71,8 @@ final class ParticleUtil {
|
||||||
double step, Particle.DustOptions dustOptions) {
|
double step, Particle.DustOptions dustOptions) {
|
||||||
double distance = Math.sqrt(
|
double distance = Math.sqrt(
|
||||||
Math.pow(x2 - x1, 2) +
|
Math.pow(x2 - x1, 2) +
|
||||||
Math.pow(y2 - y1, 2) +
|
Math.pow(y2 - y1, 2) +
|
||||||
Math.pow(z2 - z1, 2)
|
Math.pow(z2 - z1, 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
int count = (int) (distance / step) + 1;
|
int count = (int) (distance / step) + 1;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.loki.lomines.wand;
|
package dev.loki.lomines.wand;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.wand.group.GroupWandItem;
|
||||||
|
import dev.loki.lomines.wand.group.GroupWandSession;
|
||||||
import org.bukkit.Color;
|
import org.bukkit.Color;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
@ -16,13 +18,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*/
|
*/
|
||||||
public final class WandParticleService {
|
public final class WandParticleService {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
|
||||||
private final Map<UUID, BukkitRunnable> activeTasks = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private static final Color COLOR_POS1 = Color.LIME;
|
private static final Color COLOR_POS1 = Color.LIME;
|
||||||
private static final Color COLOR_POS2 = Color.AQUA;
|
private static final Color COLOR_POS2 = Color.AQUA;
|
||||||
private static final Color COLOR_EDGE = Color.YELLOW;
|
private static final Color COLOR_EDGE = Color.YELLOW;
|
||||||
private static final Color COLOR_READY = Color.GREEN;
|
private static final Color COLOR_READY = Color.GREEN;
|
||||||
|
private final LoMinesPlugin plugin;
|
||||||
|
private final Map<UUID, BukkitRunnable> activeTasks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public WandParticleService(LoMinesPlugin plugin) {
|
public WandParticleService(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ reset:
|
||||||
percent-enabled: false
|
percent-enabled: false
|
||||||
|
|
||||||
# Commands to run on reset (%mine%, %player%, %blocks% placeholders)
|
# Commands to run on reset (%mine%, %player%, %blocks% placeholders)
|
||||||
commands: []
|
commands: [ ]
|
||||||
# - "broadcast Mine %mine% has been reset!"
|
# - "broadcast Mine %mine% has been reset!"
|
||||||
# - "eco give %player% 10"
|
# - "eco give %player% 10"
|
||||||
|
|
||||||
# Broadcast message on reset (empty = no broadcast)
|
# Broadcast message on reset (empty = no broadcast)
|
||||||
broadcast: ""
|
broadcast: ""
|
||||||
|
|
@ -28,7 +28,7 @@ blocks:
|
||||||
# For MASK mode: which block marks fill positions
|
# For MASK mode: which block marks fill positions
|
||||||
mask:
|
mask:
|
||||||
marker: "pink_concrete"
|
marker: "pink_concrete"
|
||||||
positions: []
|
positions: [ ]
|
||||||
|
|
||||||
# UI settings
|
# UI settings
|
||||||
ui:
|
ui:
|
||||||
|
|
@ -43,7 +43,7 @@ ui:
|
||||||
timer-format: "mm:ss"
|
timer-format: "mm:ss"
|
||||||
|
|
||||||
# Rewards for mining specific blocks
|
# Rewards for mining specific blocks
|
||||||
rewards: []
|
rewards: [ ]
|
||||||
# Example:
|
# Example:
|
||||||
# - chance: 5.0
|
# - chance: 5.0
|
||||||
# blocks:
|
# blocks:
|
||||||
|
|
@ -56,7 +56,7 @@ rewards: []
|
||||||
# - "<gray>Mined from the depths"
|
# - "<gray>Mined from the depths"
|
||||||
# commands:
|
# commands:
|
||||||
# - "eco give %player% 100"
|
# - "eco give %player% 100"
|
||||||
# prevent-drops: true
|
# prevent-drops: true
|
||||||
|
|
||||||
# Teleport players on reset
|
# Teleport players on reset
|
||||||
teleport:
|
teleport:
|
||||||
|
|
@ -84,12 +84,12 @@ worldguard:
|
||||||
region-template: "{mine_name}_{random_4}"
|
region-template: "{mine_name}_{random_4}"
|
||||||
|
|
||||||
# Region owners (player names or "uuid:<uuid>")
|
# Region owners (player names or "uuid:<uuid>")
|
||||||
owners: []
|
owners: [ ]
|
||||||
# - "player_name"
|
# - "player_name"
|
||||||
# - "uuid:12345678-1234-1234-1234-123456789012"
|
# - "uuid:12345678-1234-1234-1234-123456789012"
|
||||||
|
|
||||||
# Region members (player names or "uuid:<uuid>")
|
# Region members (player names or "uuid:<uuid>")
|
||||||
members: []
|
members: [ ]
|
||||||
|
|
||||||
# WorldGuard flags to set
|
# WorldGuard flags to set
|
||||||
# Можно добавить любые другие флаги: pvp, tnt, build, и т.д.
|
# Можно добавить любые другие флаги: pvp, tnt, build, и т.д.
|
||||||
|
|
|
||||||
|
|
@ -70,9 +70,9 @@ reset:
|
||||||
broadcast: "�FF00Шахта &#FFFF00{mine} �FF00сброшена!"
|
broadcast: "�FF00Шахта &#FFFF00{mine} �FF00сброшена!"
|
||||||
|
|
||||||
# Команды при сбросе (опционально)
|
# Команды при сбросе (опционально)
|
||||||
commands: []
|
commands: [ ]
|
||||||
# - "eco give <player> 100"
|
# - "eco give <player> 100"
|
||||||
# - "broadcast Шахта {mine} сброшена!"
|
# - "broadcast Шахта {mine} сброшена!"
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# ТЕЛЕПОРТАЦИЯ ПРИ СБРОСЕ
|
# ТЕЛЕПОРТАЦИЯ ПРИ СБРОСЕ
|
||||||
|
|
@ -97,7 +97,7 @@ teleport:
|
||||||
# ============================================
|
# ============================================
|
||||||
# Выдаются с определённым шансом при ломании блоков
|
# Выдаются с определённым шансом при ломании блоков
|
||||||
|
|
||||||
rewards: []
|
rewards: [ ]
|
||||||
# Пример награды:
|
# Пример награды:
|
||||||
# - chance: 0.001 # 0.1% шанс
|
# - chance: 0.001 # 0.1% шанс
|
||||||
# prevent-drops: false # Отменить дроп блока?
|
# prevent-drops: false # Отменить дроп блока?
|
||||||
|
|
@ -109,7 +109,7 @@ rewards: []
|
||||||
# amount: 1
|
# amount: 1
|
||||||
# name: "�FFFFРедкий алмаз"
|
# name: "�FFFFРедкий алмаз"
|
||||||
# commands: # Команды (опционально)
|
# commands: # Команды (опционально)
|
||||||
# - "eco give <player> 1000"
|
# - "eco give <player> 1000"
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# ИНТЕРФЕЙС (UI)
|
# ИНТЕРФЕЙС (UI)
|
||||||
|
|
@ -144,7 +144,6 @@ ui:
|
||||||
# WORLDGUARD ИНТЕГРАЦИЯ (опционально)
|
# WORLDGUARD ИНТЕГРАЦИЯ (опционально)
|
||||||
# ============================================
|
# ============================================
|
||||||
# Создаёт регион для защиты шахты
|
# Создаёт регион для защиты шахты
|
||||||
# По умолчанию: только block-break=allow (все могут ломать)
|
|
||||||
# Можно добавить ЛЮБЫЕ флаги WorldGuard!
|
# Можно добавить ЛЮБЫЕ флаги WorldGuard!
|
||||||
worldguard:
|
worldguard:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
@ -154,10 +153,10 @@ worldguard:
|
||||||
region-template: "mine_{mine_name}_{random_4}"
|
region-template: "mine_{mine_name}_{random_4}"
|
||||||
|
|
||||||
# Владельцы региона (uuid:xxx или имя)
|
# Владельцы региона (uuid:xxx или имя)
|
||||||
owners: []
|
owners: [ ]
|
||||||
|
|
||||||
# Участники региона
|
# Участники региона
|
||||||
members: []
|
members: [ ]
|
||||||
|
|
||||||
# Флаги WorldGuard. По умолчанию: только block-break=allow
|
# Флаги WorldGuard. По умолчанию: только block-break=allow
|
||||||
# МОЖНО ДОБАВИТЬ ЛЮБЫЕ ФЛАГИ:
|
# МОЖНО ДОБАВИТЬ ЛЮБЫЕ ФЛАГИ:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package dev.loki.lomines.command;
|
package dev.loki.lomines.command;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.command.admin.AdminCommands;
|
||||||
import dev.loki.lomines.core.mine.Mine;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.core.Mines;
|
import dev.loki.lomines.core.mine.Mines;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
package dev.loki.lomines.core;
|
package dev.loki.lomines.core;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
import dev.loki.lomines.block.BukkitBlockSetter;
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
import dev.loki.lomines.block.ItemsAdderBlockSetter;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
import dev.loki.lomines.block.OraxenBlockSetter;
|
import dev.loki.lomines.data.config.block.BlockConfig;
|
||||||
import dev.loki.lomines.data.MineConfig;
|
import dev.loki.lomines.data.config.block.BlockKey;
|
||||||
|
import dev.loki.lomines.data.config.region.RegionConfig;
|
||||||
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
@ -13,7 +16,6 @@ import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
@ -33,85 +35,74 @@ class MineTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
MockitoAnnotations.openMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
|
when(world.getName()).thenReturn("world");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateBlockSetter_WithOraxenPrefix_CreatesOraxenBlockSetter() {
|
void testCreateBlockSetter_WithOraxenPrefix_CreatesBukkitBlockSetter() {
|
||||||
// Arrange
|
// Oraxen integration is disabled — constructor throws IllegalArgumentException
|
||||||
Map<String, Double> blocks = new HashMap<>();
|
Map<BlockKey, Double> blocks = new HashMap<>();
|
||||||
blocks.put("oraxen:custom_ore", 50.0);
|
blocks.put(new BlockKey.Oraxen("custom_ore"), 50.0);
|
||||||
blocks.put("oraxen:rare_ore", 30.0);
|
blocks.put(new BlockKey.Oraxen("rare_ore"), 30.0);
|
||||||
|
blocks.put(new BlockKey.Oraxen("other_ore"), 20.0);
|
||||||
|
|
||||||
MineConfig config = createTestConfig(blocks);
|
MineConfig config = createTestConfig(blocks);
|
||||||
|
|
||||||
// Act
|
assertThrows(IllegalArgumentException.class,
|
||||||
Mine mine = new Mine("test_mine", config, plugin);
|
() -> new Mine("test_mine", config, plugin),
|
||||||
|
"Expected IllegalArgumentException when Oraxen integration is disabled");
|
||||||
// Assert
|
|
||||||
assertNotNull(mine.getBlockSetter());
|
|
||||||
assertInstanceOf(OraxenBlockSetter.class, mine.getBlockSetter(), "Expected OraxenBlockSetter for oraxen: prefix");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateBlockSetter_WithItemsAdderPrefix_CreatesItemsAdderBlockSetter() {
|
void testCreateBlockSetter_WithItemsAdderPrefix_CreatesBukkitBlockSetter() {
|
||||||
// Arrange
|
// ItemsAdder integration is disabled — constructor throws IllegalArgumentException
|
||||||
Map<String, Double> blocks = new HashMap<>();
|
Map<BlockKey, Double> blocks = new HashMap<>();
|
||||||
blocks.put("itemsadder:custom_block", 60.0);
|
blocks.put(new BlockKey.ItemsAdder("custom_block"), 60.0);
|
||||||
blocks.put("itemsadder:special_block", 40.0);
|
blocks.put(new BlockKey.ItemsAdder("special_block"), 40.0);
|
||||||
|
|
||||||
MineConfig config = createTestConfig(blocks);
|
MineConfig config = createTestConfig(blocks);
|
||||||
|
|
||||||
// Act
|
assertThrows(IllegalArgumentException.class,
|
||||||
Mine mine = new Mine("test_mine", config, plugin);
|
() -> new Mine("test_mine", config, plugin),
|
||||||
|
"Expected IllegalArgumentException when ItemsAdder integration is disabled");
|
||||||
// Assert
|
|
||||||
assertNotNull(mine.getBlockSetter());
|
|
||||||
assertInstanceOf(ItemsAdderBlockSetter.class, mine.getBlockSetter(), "Expected ItemsAdderBlockSetter for itemsadder: prefix");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateBlockSetter_WithoutPrefix_CreatesBukkitBlockSetter() {
|
void testCreateBlockSetter_WithoutPrefix_CreatesBukkitBlockSetter() {
|
||||||
// Arrange
|
Map<BlockKey, Double> blocks = new HashMap<>();
|
||||||
Map<String, Double> blocks = new HashMap<>();
|
blocks.put(new BlockKey.Vanilla(Material.STONE), 50.0);
|
||||||
blocks.put("STONE", 50.0);
|
blocks.put(new BlockKey.Vanilla(Material.COAL_ORE), 30.0);
|
||||||
blocks.put("COAL_ORE", 30.0);
|
blocks.put(new BlockKey.Vanilla(Material.IRON_ORE), 20.0);
|
||||||
blocks.put("IRON_ORE", 20.0);
|
|
||||||
|
|
||||||
MineConfig config = createTestConfig(blocks);
|
MineConfig config = createTestConfig(blocks);
|
||||||
|
|
||||||
// Act
|
|
||||||
Mine mine = new Mine("test_mine", config, plugin);
|
Mine mine = new Mine("test_mine", config, plugin);
|
||||||
|
|
||||||
// Assert
|
|
||||||
assertNotNull(mine.getBlockSetter());
|
assertNotNull(mine.getBlockSetter());
|
||||||
assertInstanceOf(BukkitBlockSetter.class, mine.getBlockSetter(), "Expected BukkitBlockSetter for vanilla blocks without prefix");
|
assertInstanceOf(dev.loki.lomines.block.BukkitBlockSetter.class, mine.getBlockSetter(),
|
||||||
|
"Expected BukkitBlockSetter for vanilla blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateBlockSetter_WithEmptyBlocks_ThrowsException() {
|
void testCreateBlockSetter_WithEmptyBlocks_ThrowsException() {
|
||||||
// Arrange
|
Map<BlockKey, Double> blocks = new HashMap<>();
|
||||||
Map<String, Double> blocks = new HashMap<>();
|
|
||||||
MineConfig config = createTestConfig(blocks);
|
|
||||||
|
|
||||||
// Act & Assert
|
assertThrows(
|
||||||
IllegalArgumentException exception = assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() -> new Mine("test_mine", config, plugin)
|
() -> new BlockConfig(blocks, dev.loki.lomines.data.config.block.FillMode.CUBOID, null)
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals("Mine must have at least one block type", exception.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MineConfig createTestConfig(Map<String, Double> blocks) {
|
private MineConfig createTestConfig(Map<BlockKey, Double> blocks) {
|
||||||
when(world.getName()).thenReturn("world");
|
|
||||||
|
|
||||||
Location loc1 = new Location(world, 0, 0, 0);
|
Location loc1 = new Location(world, 0, 0, 0);
|
||||||
Location loc2 = new Location(world, 10, 10, 10);
|
Location loc2 = new Location(world, 10, 10, 10);
|
||||||
|
|
||||||
return MineConfig.builder()
|
RegionConfig region = RegionConfig.single(new Cuboid(loc1, loc2));
|
||||||
.selections(List.of(loc1, loc2))
|
BlockConfig blockConfig = new BlockConfig(blocks, dev.loki.lomines.data.config.block.FillMode.CUBOID, null);
|
||||||
.blocks(blocks)
|
|
||||||
.resetTicks(6000)
|
return MineConfig.builder("test_mine")
|
||||||
|
.region(region)
|
||||||
|
.blocks(blockConfig)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.loki.lomines.core;
|
package dev.loki.lomines.core;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.core.mine.MineTicker;
|
||||||
|
import dev.loki.lomines.core.mine.Mines;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.loki.lomines.core;
|
package dev.loki.lomines.core;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.core.mine.Mine;
|
||||||
|
import dev.loki.lomines.core.mine.Mines;
|
||||||
import dev.lolib.core.LoLogger;
|
import dev.lolib.core.LoLogger;
|
||||||
import dev.lolib.scheduler.ScheduledTask;
|
import dev.lolib.scheduler.ScheduledTask;
|
||||||
import dev.lolib.scheduler.Scheduler;
|
import dev.lolib.scheduler.Scheduler;
|
||||||
|
|
@ -9,6 +11,7 @@ import org.bukkit.Material;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
@ -25,18 +28,36 @@ import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for Mines registry.
|
* Unit tests for Mines registry.
|
||||||
* Tests loading and creating mines.
|
|
||||||
*/
|
*/
|
||||||
class MinesTest {
|
class MinesTest {
|
||||||
|
|
||||||
@TempDir
|
@TempDir
|
||||||
Path tempDir;
|
Path tempDir;
|
||||||
|
|
||||||
private Mines mines;
|
private Mines mines;
|
||||||
private LoMinesPlugin plugin;
|
private LoMinesPlugin plugin;
|
||||||
private Scheduler scheduler;
|
private Scheduler scheduler;
|
||||||
|
// Keep Bukkit mock open for the whole test — WorldGuardRegionService calls
|
||||||
|
// Bukkit.getPluginManager() in the Mines constructor.
|
||||||
|
private MockedStatic<Bukkit> globalBukkit;
|
||||||
|
private MockedStatic<Scheduler> globalScheduler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
globalBukkit = mockStatic(Bukkit.class);
|
||||||
|
globalScheduler = mockStatic(Scheduler.class);
|
||||||
|
|
||||||
|
PluginManager pluginManager = mock(org.bukkit.plugin.PluginManager.class);
|
||||||
|
Server server = mock(Server.class);
|
||||||
|
World world = mock(World.class);
|
||||||
|
BlockData blockData = mock(BlockData.class);
|
||||||
|
|
||||||
|
globalBukkit.when(Bukkit::getPluginManager).thenReturn(pluginManager);
|
||||||
|
globalBukkit.when(Bukkit::getServer).thenReturn(server);
|
||||||
|
globalBukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||||
|
globalBukkit.when(() -> Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
|
||||||
|
when(world.getName()).thenReturn("world");
|
||||||
|
|
||||||
plugin = mock(LoMinesPlugin.class);
|
plugin = mock(LoMinesPlugin.class);
|
||||||
Logger logger = mock(Logger.class);
|
Logger logger = mock(Logger.class);
|
||||||
LoLogger loLogger = mock(LoLogger.class);
|
LoLogger loLogger = mock(LoLogger.class);
|
||||||
|
|
@ -46,59 +67,37 @@ class MinesTest {
|
||||||
when(plugin.getLogger()).thenReturn(logger);
|
when(plugin.getLogger()).thenReturn(logger);
|
||||||
when(plugin.loLogger()).thenReturn(loLogger);
|
when(plugin.loLogger()).thenReturn(loLogger);
|
||||||
|
|
||||||
|
globalScheduler.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
|
||||||
|
ScheduledTask task = mock(ScheduledTask.class);
|
||||||
|
when(scheduler.runTimer(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
||||||
|
|
||||||
mines = new Mines(plugin);
|
mines = new Mines(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@AfterEach
|
||||||
* Helper method to set up Bukkit and Scheduler mocking for tests that create mines.
|
void tearDown() {
|
||||||
*/
|
if (globalScheduler != null) globalScheduler.close();
|
||||||
private void setupBukkitAndScheduler(MockedStatic<Bukkit> bukkit, MockedStatic<Scheduler> schedulerStatic) {
|
if (globalBukkit != null) globalBukkit.close();
|
||||||
Server server = mock(Server.class);
|
|
||||||
World world = mock(World.class);
|
|
||||||
BlockData blockData = mock(BlockData.class);
|
|
||||||
|
|
||||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
|
||||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
|
||||||
bukkit.when(() -> Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
|
|
||||||
|
|
||||||
when(world.getName()).thenReturn("world");
|
|
||||||
|
|
||||||
schedulerStatic.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
|
|
||||||
|
|
||||||
// Mock scheduler methods to execute callbacks immediately for testing
|
|
||||||
ScheduledTask task = mock(ScheduledTask.class);
|
|
||||||
when(scheduler.runTimer(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllWithNoMinesFolder() throws IOException {
|
void testLoadAllWithNoMinesFolder() throws IOException {
|
||||||
// When mines folder doesn't exist, loadAll should not throw
|
|
||||||
assertDoesNotThrow(() -> mines.loadAll());
|
assertDoesNotThrow(() -> mines.loadAll());
|
||||||
|
|
||||||
// No mines should be loaded
|
|
||||||
assertEquals(0, mines.getAll().size());
|
assertEquals(0, mines.getAll().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllWithEmptyMinesFolder() throws IOException {
|
void testLoadAllWithEmptyMinesFolder() throws IOException {
|
||||||
// Create empty mines folder
|
Files.createDirectories(tempDir.resolve("mines"));
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
|
||||||
Files.createDirectories(minesFolder);
|
|
||||||
|
|
||||||
// Load all mines
|
|
||||||
mines.loadAll();
|
mines.loadAll();
|
||||||
|
|
||||||
// No mines should be loaded
|
|
||||||
assertEquals(0, mines.getAll().size());
|
assertEquals(0, mines.getAll().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllWithValidMine() throws IOException {
|
void testLoadAllWithValidMine() throws IOException {
|
||||||
// Create mines folder
|
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
Path minesFolder = tempDir.resolve("mines");
|
||||||
Files.createDirectories(minesFolder);
|
Files.createDirectories(minesFolder);
|
||||||
|
|
||||||
// Create a valid mine config file
|
|
||||||
String yamlContent = """
|
String yamlContent = """
|
||||||
selection.1: world;0;64;0;0.0;0.0
|
selection.1: world;0;64;0;0.0;0.0
|
||||||
selection.2: world;10;74;10;0.0;0.0
|
selection.2: world;10;74;10;0.0;0.0
|
||||||
|
|
@ -118,36 +117,22 @@ class MinesTest {
|
||||||
broadcast-reset: ""
|
broadcast-reset: ""
|
||||||
random-rewards: []
|
random-rewards: []
|
||||||
""";
|
""";
|
||||||
|
Files.writeString(minesFolder.resolve("testmine.yml"), yamlContent);
|
||||||
|
|
||||||
Path configFile = minesFolder.resolve("testmine.yml");
|
mines.loadAll();
|
||||||
Files.writeString(configFile, yamlContent);
|
|
||||||
|
|
||||||
// Mock Bukkit and Scheduler
|
assertEquals(1, mines.getAll().size());
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
assertTrue(mines.find("testmine").isPresent());
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
Mine mine = mines.get("testmine");
|
||||||
|
assertNotNull(mine);
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
assertEquals("testmine", mine.getName());
|
||||||
|
|
||||||
// Load all mines
|
|
||||||
mines.loadAll();
|
|
||||||
|
|
||||||
// Verify mine was loaded
|
|
||||||
assertEquals(1, mines.getAll().size());
|
|
||||||
assertTrue(mines.find("testmine").isPresent());
|
|
||||||
|
|
||||||
Mine mine = mines.get("testmine");
|
|
||||||
assertNotNull(mine);
|
|
||||||
assertEquals("testmine", mine.getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllWithMultipleMines() throws IOException {
|
void testLoadAllWithMultipleMines() throws IOException {
|
||||||
// Create mines folder
|
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
Path minesFolder = tempDir.resolve("mines");
|
||||||
Files.createDirectories(minesFolder);
|
Files.createDirectories(minesFolder);
|
||||||
|
|
||||||
// Create multiple mine config files
|
|
||||||
String yamlContent = """
|
String yamlContent = """
|
||||||
selection.1: world;0;64;0;0.0;0.0
|
selection.1: world;0;64;0;0.0;0.0
|
||||||
selection.2: world;10;74;10;0.0;0.0
|
selection.2: world;10;74;10;0.0;0.0
|
||||||
|
|
@ -167,35 +152,23 @@ class MinesTest {
|
||||||
broadcast-reset: ""
|
broadcast-reset: ""
|
||||||
random-rewards: []
|
random-rewards: []
|
||||||
""";
|
""";
|
||||||
|
|
||||||
Files.writeString(minesFolder.resolve("mine1.yml"), yamlContent);
|
Files.writeString(minesFolder.resolve("mine1.yml"), yamlContent);
|
||||||
Files.writeString(minesFolder.resolve("mine2.yml"), yamlContent);
|
Files.writeString(minesFolder.resolve("mine2.yml"), yamlContent);
|
||||||
Files.writeString(minesFolder.resolve("mine3.yml"), yamlContent);
|
Files.writeString(minesFolder.resolve("mine3.yml"), yamlContent);
|
||||||
|
|
||||||
// Mock Bukkit and Scheduler
|
mines.loadAll();
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
assertEquals(3, mines.getAll().size());
|
||||||
|
assertTrue(mines.find("mine1").isPresent());
|
||||||
// Load all mines
|
assertTrue(mines.find("mine2").isPresent());
|
||||||
mines.loadAll();
|
assertTrue(mines.find("mine3").isPresent());
|
||||||
|
|
||||||
// Verify all mines were loaded
|
|
||||||
assertEquals(3, mines.getAll().size());
|
|
||||||
assertTrue(mines.find("mine1").isPresent());
|
|
||||||
assertTrue(mines.find("mine2").isPresent());
|
|
||||||
assertTrue(mines.find("mine3").isPresent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllIgnoresNonYamlFiles() throws IOException {
|
void testLoadAllIgnoresNonYamlFiles() throws IOException {
|
||||||
// Create mines folder
|
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
Path minesFolder = tempDir.resolve("mines");
|
||||||
Files.createDirectories(minesFolder);
|
Files.createDirectories(minesFolder);
|
||||||
|
|
||||||
// Create a valid mine config file
|
|
||||||
String yamlContent = """
|
String yamlContent = """
|
||||||
selection.1: world;0;64;0;0.0;0.0
|
selection.1: world;0;64;0;0.0;0.0
|
||||||
selection.2: world;10;74;10;0.0;0.0
|
selection.2: world;10;74;10;0.0;0.0
|
||||||
|
|
@ -205,196 +178,87 @@ class MinesTest {
|
||||||
ticks: 6000
|
ticks: 6000
|
||||||
percent: 10.0
|
percent: 10.0
|
||||||
""";
|
""";
|
||||||
|
|
||||||
Files.writeString(minesFolder.resolve("validmine.yml"), yamlContent);
|
Files.writeString(minesFolder.resolve("validmine.yml"), yamlContent);
|
||||||
Files.writeString(minesFolder.resolve("readme.txt"), "This is not a mine config");
|
Files.writeString(minesFolder.resolve("readme.txt"), "not a mine config");
|
||||||
Files.writeString(minesFolder.resolve("backup.bak"), "Backup file");
|
Files.writeString(minesFolder.resolve("backup.bak"), "backup file");
|
||||||
|
|
||||||
// Mock Bukkit and Scheduler
|
mines.loadAll();
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
assertEquals(1, mines.getAll().size());
|
||||||
|
assertTrue(mines.find("validmine").isPresent());
|
||||||
// Load all mines
|
|
||||||
mines.loadAll();
|
|
||||||
|
|
||||||
// Only the .yml file should be loaded
|
|
||||||
assertEquals(1, mines.getAll().size());
|
|
||||||
assertTrue(mines.find("validmine").isPresent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoadAllWithInvalidMine() throws IOException {
|
void testLoadAllWithInvalidMine() throws IOException {
|
||||||
// Create mines folder
|
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
Path minesFolder = tempDir.resolve("mines");
|
||||||
Files.createDirectories(minesFolder);
|
Files.createDirectories(minesFolder);
|
||||||
|
Files.writeString(minesFolder.resolve("invalidmine.yml"), "selection.1: world;0;64;0;0.0;0.0\n");
|
||||||
|
|
||||||
// Create an invalid mine config file (missing required fields)
|
assertDoesNotThrow(() -> mines.loadAll());
|
||||||
String invalidYaml = """
|
assertEquals(0, mines.getAll().size());
|
||||||
selection.1: world;0;64;0;0.0;0.0
|
verify(plugin.loLogger(), atLeastOnce()).error(anyString());
|
||||||
""";
|
|
||||||
|
|
||||||
Files.writeString(minesFolder.resolve("invalidmine.yml"), invalidYaml);
|
|
||||||
|
|
||||||
// Mock Bukkit and Scheduler
|
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
|
||||||
|
|
||||||
// Load all mines - should not throw, but should log error
|
|
||||||
assertDoesNotThrow(() -> mines.loadAll());
|
|
||||||
|
|
||||||
// Invalid mine should not be loaded
|
|
||||||
assertEquals(0, mines.getAll().size());
|
|
||||||
|
|
||||||
// Verify error was logged
|
|
||||||
verify(plugin.loLogger(), atLeastOnce()).error(anyString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateNewMine() throws IOException {
|
void testCreateNewMine() throws IOException {
|
||||||
// Mock Bukkit and Scheduler
|
mines.create("newmine");
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
assertEquals(1, mines.getAll().size());
|
||||||
|
assertTrue(mines.find("newmine").isPresent());
|
||||||
// Create a new mine
|
Mine mine = mines.get("newmine");
|
||||||
mines.create("newmine");
|
assertNotNull(mine);
|
||||||
|
assertEquals("newmine", mine.getName());
|
||||||
// Verify mine was created
|
assertTrue(Files.exists(tempDir.resolve("mines/newmine.yml")));
|
||||||
assertEquals(1, mines.getAll().size());
|
verify(plugin.loLogger()).info("Created mine: newmine");
|
||||||
assertTrue(mines.find("newmine").isPresent());
|
|
||||||
|
|
||||||
Mine mine = mines.get("newmine");
|
|
||||||
assertNotNull(mine);
|
|
||||||
assertEquals("newmine", mine.getName());
|
|
||||||
|
|
||||||
// Verify config file was created
|
|
||||||
Path configFile = tempDir.resolve("mines/newmine.yml");
|
|
||||||
assertTrue(Files.exists(configFile));
|
|
||||||
|
|
||||||
// Verify logger was called
|
|
||||||
verify(plugin.loLogger()).info("Created mine: newmine");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateMineCreatesFolder() throws IOException {
|
void testCreateMineCreatesFolder() throws IOException {
|
||||||
// Ensure mines folder doesn't exist
|
assertFalse(Files.exists(tempDir.resolve("mines")));
|
||||||
Path minesFolder = tempDir.resolve("mines");
|
mines.create("testmine");
|
||||||
assertFalse(Files.exists(minesFolder));
|
assertTrue(Files.isDirectory(tempDir.resolve("mines")));
|
||||||
|
|
||||||
// Mock Bukkit and Scheduler
|
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
|
||||||
|
|
||||||
// Create a new mine
|
|
||||||
mines.create("testmine");
|
|
||||||
|
|
||||||
// Verify mines folder was created
|
|
||||||
assertTrue(Files.exists(minesFolder));
|
|
||||||
assertTrue(Files.isDirectory(minesFolder));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateDuplicateMineThrowsException() throws IOException {
|
void testCreateDuplicateMineThrowsException() throws IOException {
|
||||||
// Mock Bukkit and Scheduler
|
mines.create("duplicate");
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
() -> mines.create("duplicate"));
|
||||||
|
assertTrue(ex.getMessage().contains("Mine already exists"));
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
|
||||||
|
|
||||||
// Create a mine
|
|
||||||
mines.create("duplicate");
|
|
||||||
|
|
||||||
// Try to create the same mine again
|
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
|
||||||
mines.create("duplicate");
|
|
||||||
});
|
|
||||||
|
|
||||||
assertTrue(exception.getMessage().contains("Mine already exists"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreateMineIsCaseInsensitive() throws IOException {
|
void testCreateMineIsCaseInsensitive() throws IOException {
|
||||||
// Mock Bukkit and Scheduler
|
mines.create("TestMine");
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
() -> mines.create("testmine"));
|
||||||
|
assertTrue(ex.getMessage().contains("Mine already exists"));
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
|
||||||
|
|
||||||
// Create a mine with mixed case
|
|
||||||
mines.create("TestMine");
|
|
||||||
|
|
||||||
// Try to create the same mine with different case
|
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
|
||||||
mines.create("testmine");
|
|
||||||
});
|
|
||||||
|
|
||||||
assertTrue(exception.getMessage().contains("Mine already exists"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetMineByName() throws IOException {
|
void testGetMineByName() throws IOException {
|
||||||
// Mock Bukkit and Scheduler
|
mines.create("testmine");
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
Mine mine = mines.get("testmine");
|
||||||
|
assertNotNull(mine);
|
||||||
|
assertEquals("testmine", mine.getName());
|
||||||
|
|
||||||
// Create a mine
|
Mine mine2 = mines.get("TestMine");
|
||||||
mines.create("testmine");
|
assertNotNull(mine2);
|
||||||
|
assertSame(mine, mine2);
|
||||||
// Get mine by exact name
|
|
||||||
Mine mine = mines.get("testmine");
|
|
||||||
assertNotNull(mine);
|
|
||||||
assertEquals("testmine", mine.getName());
|
|
||||||
|
|
||||||
// Get mine by different case
|
|
||||||
Mine mine2 = mines.get("TestMine");
|
|
||||||
assertNotNull(mine2);
|
|
||||||
assertEquals("testmine", mine2.getName());
|
|
||||||
|
|
||||||
// Same mine instance
|
|
||||||
assertSame(mine, mine2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetNonExistentMineThrowsException() {
|
void testGetNonExistentMineThrowsException() {
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||||
mines.get("nonexistent");
|
() -> mines.get("nonexistent"));
|
||||||
});
|
assertTrue(ex.getMessage().contains("Mine not found"));
|
||||||
|
|
||||||
assertTrue(exception.getMessage().contains("Mine not found"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFindMineReturnsOptional() throws IOException {
|
void testFindMineReturnsOptional() throws IOException {
|
||||||
// Mock Bukkit and Scheduler
|
mines.create("testmine");
|
||||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
assertTrue(mines.find("testmine").isPresent());
|
||||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
assertFalse(mines.find("nonexistent").isPresent());
|
||||||
|
|
||||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
|
||||||
|
|
||||||
// Create a mine
|
|
||||||
mines.create("testmine");
|
|
||||||
|
|
||||||
// Find existing mine
|
|
||||||
assertTrue(mines.find("testmine").isPresent());
|
|
||||||
|
|
||||||
// Find non-existent mine
|
|
||||||
assertFalse(mines.find("nonexistent").isPresent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package dev.loki.lomines.data;
|
package dev.loki.lomines.data;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.data.stats.Leaderboard;
|
||||||
|
import dev.loki.lomines.data.stats.LeaderboardEntry;
|
||||||
|
import dev.loki.lomines.data.stats.StatsManager;
|
||||||
import dev.lolib.core.LoLogger;
|
import dev.lolib.core.LoLogger;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
@ -48,7 +51,7 @@ class LeaderboardCacheIntegrationTest {
|
||||||
// Build cache
|
// Build cache
|
||||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||||
assertEquals(1, top1.size(), "Should have 1 player initially");
|
assertEquals(1, top1.size(), "Should have 1 player initially");
|
||||||
assertEquals(player1, top1.get(0).getPlayerId());
|
assertEquals(player1, top1.get(0).playerId());
|
||||||
|
|
||||||
// Increment blocks for player2 - this should invalidate cache
|
// Increment blocks for player2 - this should invalidate cache
|
||||||
statsManager.incrementBlocks(player2, "mine1");
|
statsManager.incrementBlocks(player2, "mine1");
|
||||||
|
|
@ -58,8 +61,8 @@ class LeaderboardCacheIntegrationTest {
|
||||||
assertEquals(2, top2.size(), "Should have 2 players after increment");
|
assertEquals(2, top2.size(), "Should have 2 players after increment");
|
||||||
|
|
||||||
// Verify order (player1 has 100, player2 has 1)
|
// Verify order (player1 has 100, player2 has 1)
|
||||||
assertEquals(player1, top2.get(0).getPlayerId(), "Player1 should still be first");
|
assertEquals(player1, top2.get(0).playerId(), "Player1 should still be first");
|
||||||
assertEquals(player2, top2.get(1).getPlayerId(), "Player2 should be second");
|
assertEquals(player2, top2.get(1).playerId(), "Player2 should be second");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -73,7 +76,7 @@ class LeaderboardCacheIntegrationTest {
|
||||||
|
|
||||||
// Build cache
|
// Build cache
|
||||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||||
assertEquals(player2, top1.get(0).getPlayerId(), "Player2 should be first initially");
|
assertEquals(player2, top1.get(0).playerId(), "Player2 should be first initially");
|
||||||
|
|
||||||
// Increment player1 many times to overtake player2
|
// Increment player1 many times to overtake player2
|
||||||
for (int i = 0; i < 60; i++) {
|
for (int i = 0; i < 60; i++) {
|
||||||
|
|
@ -82,10 +85,10 @@ class LeaderboardCacheIntegrationTest {
|
||||||
|
|
||||||
// Get top again - cache should be rebuilt with new order
|
// Get top again - cache should be rebuilt with new order
|
||||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||||
assertEquals(player1, top2.get(0).getPlayerId(), "Player1 should be first after increments");
|
assertEquals(player1, top2.get(0).playerId(), "Player1 should be first after increments");
|
||||||
assertEquals(110, top2.get(0).getCount(), "Player1 should have 110 blocks");
|
assertEquals(110, top2.get(0).count(), "Player1 should have 110 blocks");
|
||||||
assertEquals(player2, top2.get(1).getPlayerId(), "Player2 should be second");
|
assertEquals(player2, top2.get(1).playerId(), "Player2 should be second");
|
||||||
assertEquals(100, top2.get(1).getCount(), "Player2 should still have 100 blocks");
|
assertEquals(100, top2.get(1).count(), "Player2 should still have 100 blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -104,7 +107,7 @@ class LeaderboardCacheIntegrationTest {
|
||||||
// Get top - should show updated count
|
// Get top - should show updated count
|
||||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||||
assertEquals(1, top2.size());
|
assertEquals(1, top2.size());
|
||||||
assertEquals(5, top2.get(0).getCount(), "Should have 5 blocks after 5 increments");
|
assertEquals(5, top2.get(0).count(), "Should have 5 blocks after 5 increments");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -150,7 +153,7 @@ class LeaderboardCacheIntegrationTest {
|
||||||
// Get with limit 2 - should use same cache
|
// Get with limit 2 - should use same cache
|
||||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(2);
|
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(2);
|
||||||
assertEquals(2, top2.size());
|
assertEquals(2, top2.size());
|
||||||
assertEquals(player3, top2.get(0).getPlayerId(), "Should have highest player");
|
assertEquals(player3, top2.get(0).playerId(), "Should have highest player");
|
||||||
assertEquals(player2, top2.get(1).getPlayerId(), "Should have second highest player");
|
assertEquals(player2, top2.get(1).playerId(), "Should have second highest player");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package dev.loki.lomines.data;
|
package dev.loki.lomines.data;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.data.stats.Leaderboard;
|
||||||
|
import dev.loki.lomines.data.stats.LeaderboardEntry;
|
||||||
|
import dev.loki.lomines.data.stats.PlayerStats;
|
||||||
|
import dev.loki.lomines.data.stats.StatsManager;
|
||||||
import dev.lolib.core.LoLogger;
|
import dev.lolib.core.LoLogger;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
@ -51,8 +55,8 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||||
assertEquals(1, top.size());
|
assertEquals(1, top.size());
|
||||||
assertEquals(playerId, top.get(0).getPlayerId());
|
assertEquals(playerId, top.get(0).playerId());
|
||||||
assertEquals(100, top.get(0).getCount());
|
assertEquals(100, top.get(0).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -67,9 +71,9 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||||
assertEquals(3, top.size());
|
assertEquals(3, top.size());
|
||||||
assertEquals(player2, top.get(0).getPlayerId()); // 200 blocks
|
assertEquals(player2, top.get(0).playerId()); // 200 blocks
|
||||||
assertEquals(player3, top.get(1).getPlayerId()); // 100 blocks
|
assertEquals(player3, top.get(1).playerId()); // 100 blocks
|
||||||
assertEquals(player1, top.get(2).getPlayerId()); // 50 blocks
|
assertEquals(player1, top.get(2).playerId()); // 50 blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -93,7 +97,7 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||||
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
||||||
assertEquals(player1, top.get(0).getPlayerId());
|
assertEquals(player1, top.get(0).playerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -108,7 +112,7 @@ class LeaderboardTest {
|
||||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||||
|
|
||||||
assertEquals(top1.size(), top2.size());
|
assertEquals(top1.size(), top2.size());
|
||||||
assertEquals(top1.get(0).getPlayerId(), top2.get(0).getPlayerId());
|
assertEquals(top1.get(0).playerId(), top2.get(0).playerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -129,7 +133,7 @@ class LeaderboardTest {
|
||||||
// Should rebuild cache with new player
|
// Should rebuild cache with new player
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||||
assertEquals(2, top.size(), "Cache should be rebuilt after invalidation");
|
assertEquals(2, top.size(), "Cache should be rebuilt after invalidation");
|
||||||
assertEquals(player2, top.get(0).getPlayerId(), "New player should be first");
|
assertEquals(player2, top.get(0).playerId(), "New player should be first");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -144,9 +148,9 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||||
assertEquals(3, top.size());
|
assertEquals(3, top.size());
|
||||||
assertEquals(player2, top.get(0).getPlayerId()); // 200 blocks
|
assertEquals(player2, top.get(0).playerId()); // 200 blocks
|
||||||
assertEquals(player3, top.get(1).getPlayerId()); // 100 blocks
|
assertEquals(player3, top.get(1).playerId()); // 100 blocks
|
||||||
assertEquals(player1, top.get(2).getPlayerId()); // 50 blocks
|
assertEquals(player1, top.get(2).playerId()); // 50 blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -159,7 +163,7 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||||
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
||||||
assertEquals(player1, top.get(0).getPlayerId());
|
assertEquals(player1, top.get(0).playerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -172,7 +176,7 @@ class LeaderboardTest {
|
||||||
|
|
||||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||||
assertEquals(1, top.size(), "Should only include players with blocks in specified mine");
|
assertEquals(1, top.size(), "Should only include players with blocks in specified mine");
|
||||||
assertEquals(player1, top.get(0).getPlayerId());
|
assertEquals(player1, top.get(0).playerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.loki.lomines.data;
|
package dev.loki.lomines.data;
|
||||||
|
|
||||||
import dev.loki.lomines.LoMinesPlugin;
|
import dev.loki.lomines.LoMinesPlugin;
|
||||||
|
import dev.loki.lomines.data.stats.PlayerStats;
|
||||||
|
import dev.loki.lomines.data.stats.StatsManager;
|
||||||
import dev.lolib.core.LoLogger;
|
import dev.lolib.core.LoLogger;
|
||||||
import dev.lolib.scheduler.ScheduledTask;
|
import dev.lolib.scheduler.ScheduledTask;
|
||||||
import dev.lolib.scheduler.Scheduler;
|
import dev.lolib.scheduler.Scheduler;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ class UIConfigTest {
|
||||||
true,
|
true,
|
||||||
"<red>{mine}</red>",
|
"<red>{mine}</red>",
|
||||||
100.0,
|
100.0,
|
||||||
"HH:mm:ss"
|
"HH:mm:ss",
|
||||||
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertTrue(config.actionBarEnabled());
|
assertTrue(config.actionBarEnabled());
|
||||||
|
|
@ -44,7 +45,7 @@ class UIConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNullFormatDefaults() {
|
void testNullFormatDefaults() {
|
||||||
UIConfig config = new UIConfig(true, null, 50.0, null);
|
UIConfig config = new UIConfig(true, null, 50.0, null, null);
|
||||||
|
|
||||||
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
|
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
|
||||||
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
|
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
|
||||||
|
|
@ -52,7 +53,7 @@ class UIConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBlankFormatDefaults() {
|
void testBlankFormatDefaults() {
|
||||||
UIConfig config = new UIConfig(true, " ", 50.0, " ");
|
UIConfig config = new UIConfig(true, " ", 50.0, " ", null);
|
||||||
|
|
||||||
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
|
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
|
||||||
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
|
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
|
||||||
|
|
@ -60,14 +61,14 @@ class UIConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNegativeRangeClamped() {
|
void testNegativeRangeClamped() {
|
||||||
UIConfig config = new UIConfig(true, "test", -10.0, "mm:ss");
|
UIConfig config = new UIConfig(true, "test", -10.0, "mm:ss", null);
|
||||||
|
|
||||||
assertEquals(1.0, config.actionBarRange());
|
assertEquals(1.0, config.actionBarRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRangeSquared() {
|
void testRangeSquared() {
|
||||||
UIConfig config = new UIConfig(true, "test", 50.0, "mm:ss");
|
UIConfig config = new UIConfig(true, "test", 50.0, "mm:ss", null);
|
||||||
|
|
||||||
assertEquals(2500.0, config.actionBarRangeSquared(), 0.001);
|
assertEquals(2500.0, config.actionBarRangeSquared(), 0.001);
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +86,7 @@ class UIConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFormatTimerMmSs() {
|
void testFormatTimerMmSs() {
|
||||||
UIConfig config = new UIConfig(true, "", 0, "mm:ss");
|
UIConfig config = new UIConfig(true, "", 0, "mm:ss", null);
|
||||||
|
|
||||||
assertEquals("00:30", config.formatTimer(30));
|
assertEquals("00:30", config.formatTimer(30));
|
||||||
assertEquals("05:00", config.formatTimer(300));
|
assertEquals("05:00", config.formatTimer(300));
|
||||||
|
|
@ -94,7 +95,7 @@ class UIConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFormatTimerHhMmSs() {
|
void testFormatTimerHhMmSs() {
|
||||||
UIConfig config = new UIConfig(true, "", 0, "HH:mm:ss");
|
UIConfig config = new UIConfig(true, "", 0, "HH:mm:ss", null);
|
||||||
|
|
||||||
assertEquals("0:00:30", config.formatTimer(30));
|
assertEquals("0:00:30", config.formatTimer(30));
|
||||||
assertEquals("0:05:00", config.formatTimer(300));
|
assertEquals("0:05:00", config.formatTimer(300));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.loki.lomines.util;
|
package dev.loki.lomines.util;
|
||||||
|
|
||||||
|
import dev.loki.lomines.util.format.ChunkUtils;
|
||||||
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.loki.lomines.util;
|
package dev.loki.lomines.util;
|
||||||
|
|
||||||
import dev.loki.lomines.data.config.parser.ConfigParseException;
|
import dev.loki.lomines.data.config.parser.ConfigParseException;
|
||||||
|
import dev.loki.lomines.util.location.LocationParser;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.loki.lomines.util;
|
package dev.loki.lomines.util;
|
||||||
|
|
||||||
|
import dev.loki.lomines.util.format.TimeFormatter;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.loki.lomines.util.selection;
|
package dev.loki.lomines.util.selection;
|
||||||
|
|
||||||
|
import dev.loki.lomines.util.location.Cuboid;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue