mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-19 15:09:25 +00:00
1.5.0-SNAPSHOT
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
MCBBS发布帖: https://www.mcbbs.net/thread-1342178-1-1.html
|
||||
|
||||
MineDown: https://github.com/Phoenix616/MineDown
|
||||
96
build.gradle
Normal file
96
build.gradle
Normal file
@@ -0,0 +1,96 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
||||
}
|
||||
|
||||
|
||||
group = 'net.momirealms'
|
||||
version = '1.5.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = 'papermc-repo'
|
||||
url = 'https://papermc.io/repo/repository/maven-public/'
|
||||
}
|
||||
maven {
|
||||
name = 'sonatype'
|
||||
url = 'https://oss.sonatype.org/content/groups/public/'
|
||||
}
|
||||
maven {
|
||||
name = "sonatype-oss-snapshots1"
|
||||
url = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
maven {
|
||||
name = "dmulloy2-repo"
|
||||
url = "https://repo.dmulloy2.net/repository/public/"
|
||||
}
|
||||
maven {
|
||||
name = "clip-repo"
|
||||
url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/'
|
||||
}
|
||||
maven {
|
||||
name = "NBT-API"
|
||||
url = "https://repo.codemc.org/repository/maven-public/"
|
||||
}
|
||||
maven {
|
||||
name = "sk89q-repo"
|
||||
url = "https://maven.enginehub.org/repo/"
|
||||
}
|
||||
maven {
|
||||
name = "Lumine Releases"
|
||||
url = "https://mvn.lumine.io/repository/maven-public"
|
||||
}
|
||||
maven {
|
||||
name = "jitpack-repo"
|
||||
url = "https://jitpack.io"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT'
|
||||
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.8.0"
|
||||
compileOnly 'me.clip:placeholderapi:2.11.1'
|
||||
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7'
|
||||
compileOnly 'io.lumine:Mythic-Dist:5.0.3-SNAPSHOT'
|
||||
compileOnly 'com.github.LoneDev6:api-itemsadder:3.2.0c-beta6'
|
||||
compileOnly fileTree(dir:'libs',includes:['*jar'])
|
||||
implementation("net.kyori:adventure-api:4.11.0")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.1.1")
|
||||
implementation("net.kyori:adventure-text-minimessage:4.11.0")
|
||||
implementation 'de.tr7zw:item-nbt-api:2.10.0'
|
||||
}
|
||||
|
||||
def targetJavaVersion = 16
|
||||
java {
|
||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
if (JavaVersion.current() < javaVersion) {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||
options.release = targetJavaVersion
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
def props = [version: version]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
expand props
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate 'net.kyori', 'libs.kyori'
|
||||
relocate 'de.tr7zw', 'libs.tr7zw'
|
||||
}
|
||||
0
gradle.properties
Normal file
0
gradle.properties
Normal file
234
gradlew
vendored
Normal file
234
gradlew
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright ? 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?,
|
||||
# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?;
|
||||
# * compound commands having a testable exit status, especially ?case?;
|
||||
# * various built-in commands including ?command?, ?set?, and ?ulimit?.
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/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
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || 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
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
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
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# 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" "$@"
|
||||
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="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!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
96
pom.xml
96
pom.xml
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.momirealms</groupId>
|
||||
<artifactId>CustomCrops</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>CustomCrops</name>
|
||||
|
||||
<properties>
|
||||
<java.version>16</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sk89q-repo</id>
|
||||
<url>https://maven.enginehub.org/repo/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype-oss-snapshots1</id>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc-repo</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack-repo</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.17.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.LoneDev6</groupId>
|
||||
<artifactId>api-itemsadder</artifactId>
|
||||
<version>3.1.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q.worldguard</groupId>
|
||||
<artifactId>worldguard-bukkit</artifactId>
|
||||
<version>7.0.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
1
settings.gradle
Normal file
1
settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'CustomCrops'
|
||||
432
src/main/java/net/momirealms/customcrops/ConfigReader.java
Normal file
432
src/main/java/net/momirealms/customcrops/ConfigReader.java
Normal file
@@ -0,0 +1,432 @@
|
||||
package net.momirealms.customcrops;
|
||||
|
||||
import net.momirealms.customcrops.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.fertilizer.QualityCrop;
|
||||
import net.momirealms.customcrops.fertilizer.RetainingSoil;
|
||||
import net.momirealms.customcrops.fertilizer.SpeedGrow;
|
||||
import net.momirealms.customcrops.integrations.*;
|
||||
import net.momirealms.customcrops.requirements.Biome;
|
||||
import net.momirealms.customcrops.requirements.Permission;
|
||||
import net.momirealms.customcrops.requirements.Requirement;
|
||||
import net.momirealms.customcrops.requirements.YPos;
|
||||
import net.momirealms.customcrops.utils.*;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConfigReader {
|
||||
|
||||
public static HashMap<String, CropInstance> CROPS = new HashMap<>();
|
||||
public static HashMap<String, Fertilizer> FERTILIZERS = new HashMap<>();
|
||||
public static HashMap<String, WateringCan> CANS = new HashMap<>();
|
||||
public static HashMap<String, Sprinkler> SPRINKLERS = new HashMap<>();
|
||||
|
||||
private static YamlConfiguration getConfig(String configName) {
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), configName);
|
||||
if (!file.exists()) {
|
||||
CustomCrops.instance.saveResource(configName, false);
|
||||
}
|
||||
return YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
public static void ReloadConfig(){
|
||||
Config.loadConfig();
|
||||
Message.loadMessage();
|
||||
Basic.loadBasic();
|
||||
Season.loadSeason();
|
||||
cropLoad();
|
||||
fertilizerLoad();
|
||||
}
|
||||
|
||||
public static class Config{
|
||||
|
||||
public static List<World> worlds;
|
||||
public static List<String> worldNames;
|
||||
public static List<Long> cropGrowTimeList;
|
||||
public static List<Integration> integration;
|
||||
public static boolean asyncCheck;
|
||||
// public static boolean useBoneMeal;
|
||||
// public static boolean consumeWater;
|
||||
// public static double boneMealChance;
|
||||
// public static String success;
|
||||
// public static String failure;
|
||||
public static boolean enableLimit;
|
||||
public static int cropLimit;
|
||||
public static int sprinklerLimit;
|
||||
public static int yMin;
|
||||
public static int yMax;
|
||||
public static int sprinklerRefill;
|
||||
public static boolean logTime;
|
||||
public static boolean onlyLoadedGrow;
|
||||
public static boolean quality;
|
||||
public static double quality_1;
|
||||
public static double quality_2;
|
||||
|
||||
public static void loadConfig(){
|
||||
|
||||
//存读基本配置文件
|
||||
CustomCrops.instance.saveDefaultConfig();
|
||||
CustomCrops.instance.reloadConfig();
|
||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||
|
||||
//农作物生长时间点
|
||||
cropGrowTimeList = config.getLongList("config.grow-time");
|
||||
cropGrowTimeList.forEach(time -> {
|
||||
if(time < 0 || time > 23999){
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 农作物生长时间点必须位于0-23999之间");
|
||||
cropGrowTimeList.remove(time);
|
||||
}
|
||||
});
|
||||
|
||||
//异步读取时间
|
||||
asyncCheck = config.getBoolean("config.async-time-check",false);
|
||||
logTime = config.getBoolean("config.log-time-consume",false);
|
||||
onlyLoadedGrow = config.getBoolean("config.only-grow-in-loaded-chunks",true);
|
||||
|
||||
//骨粉设置(已废弃)
|
||||
// useBoneMeal = config.getBoolean("config.bone-meal.enable",false);
|
||||
// if (useBoneMeal){
|
||||
// boneMealChance = config.getDouble("config.bone-meal.chance");
|
||||
// consumeWater = config.getBoolean("config.bone-meal.consume-water");
|
||||
// success = config.getString("config.bone-meal.particle.success");
|
||||
// failure = config.getString("config.bone-meal.particle.failure");
|
||||
// }
|
||||
|
||||
//数量与高度限制
|
||||
enableLimit = config.getBoolean("config.limit.enable",true);
|
||||
if (enableLimit){
|
||||
cropLimit = config.getInt("config.limit.crop",64);
|
||||
sprinklerLimit = config.getInt("config.limit.sprinkler",16);
|
||||
}
|
||||
if (Bukkit.getServer().getClass().getPackage().getName().contains("16") || Bukkit.getServer().getClass().getPackage().getName().contains("17")){
|
||||
yMin = 0;
|
||||
yMax = 256;
|
||||
}
|
||||
if (Bukkit.getServer().getClass().getPackage().getName().contains("18") || Bukkit.getServer().getClass().getPackage().getName().contains("19")){
|
||||
yMin = -64;
|
||||
yMax = 320;
|
||||
}
|
||||
|
||||
//农作物品质处理
|
||||
quality = config.getBoolean("config.quality.enable");
|
||||
if (quality){
|
||||
String[] split = StringUtils.split(config.getString("config.quality.default-ratio"), "/");
|
||||
double[] ratios = new double[3];
|
||||
ratios[0] = Double.parseDouble(split[0]);
|
||||
ratios[1] = Double.parseDouble(split[1]);
|
||||
ratios[2] = Double.parseDouble(split[2]);
|
||||
double total = ratios[0] + ratios[1] + ratios[2];
|
||||
quality_1 = ratios[0]/total;
|
||||
quality_2 = 1 - ratios[1]/total;
|
||||
}
|
||||
|
||||
sprinklerRefill = config.getInt("config.sprinkler-refill",2);
|
||||
|
||||
//农作物生长的白名单世界
|
||||
worlds = new ArrayList<>();
|
||||
worldNames = config.getStringList("config.whitelist-worlds");
|
||||
worldNames.forEach(worldName -> {
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null){
|
||||
worldNames.remove(worldName);
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 世界" + worldName + "" + "不存在");
|
||||
}else {
|
||||
worlds.add(world);
|
||||
}
|
||||
});
|
||||
|
||||
//处理插件兼容性
|
||||
integration = new ArrayList<>();
|
||||
if(config.getBoolean("config.integration.Residence",false)){
|
||||
if(Bukkit.getPluginManager().getPlugin("Residence") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件 Residence!");
|
||||
}else {
|
||||
integration.add(new Residence());
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>检测到 <gold>Residence <color:#FFEBCD>已启用保护!");
|
||||
}
|
||||
}
|
||||
if(config.getBoolean("config.integration.Kingdoms",false)){
|
||||
if(Bukkit.getPluginManager().getPlugin("Kingdoms") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件 Kingdoms!");
|
||||
}else {
|
||||
integration.add(new KingdomsX());
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>检测到 <gold>KingdomsX <color:#FFEBCD>已启用保护!");
|
||||
}
|
||||
}
|
||||
if(config.getBoolean("config.integration.WorldGuard",false)){
|
||||
if(Bukkit.getPluginManager().getPlugin("WorldGuard") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件 WorldGuard!");
|
||||
}else {
|
||||
integration.add(new WorldGuard());
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>检测到 <gold>WorldGuard <color:#FFEBCD>已启用保护!");
|
||||
}
|
||||
}
|
||||
if(config.getBoolean("config.integration.GriefDefender",false)){
|
||||
if(Bukkit.getPluginManager().getPlugin("GriefDefender") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件 GriefDefender!");
|
||||
}else {
|
||||
integration.add(new GriefDefender());
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>检测到 <gold>GriefDefender <color:#FFEBCD>已启用保护!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Basic{
|
||||
|
||||
public static String pot;
|
||||
public static String watered_pot;
|
||||
public static String glass;
|
||||
public static String sprinkler_1;
|
||||
public static String sprinkler_2;
|
||||
public static String sprinkler_1i;
|
||||
public static String sprinkler_2i;
|
||||
public static String dead;
|
||||
public static String soilDetector;
|
||||
|
||||
public static void loadBasic(){
|
||||
YamlConfiguration config = getConfig("basic.yml");
|
||||
pot = config.getString("basic.pot");
|
||||
watered_pot = config.getString("basic.watered-pot");
|
||||
glass = config.getString("basic.greenhouse-glass");
|
||||
sprinkler_1 = config.getString("basic.sprinkler-1");
|
||||
sprinkler_2 = config.getString("basic.sprinkler-2");
|
||||
sprinkler_1i = config.getString("basic.sprinkler-1-item");
|
||||
sprinkler_2i = config.getString("basic.sprinkler-2-item");
|
||||
dead = config.getString("basic.dead-crop");
|
||||
soilDetector = StringUtils.split(config.getString("basic.soil-detector"),":")[1];
|
||||
|
||||
CANS.clear();
|
||||
if (config.contains("water-can")){
|
||||
config.getConfigurationSection("water-can").getKeys(false).forEach(key -> {
|
||||
if (key.equals(StringUtils.split(config.getString("water-can." + key + ".item"),":")[1])){
|
||||
int width = config.getInt("water-can." + key + ".width");
|
||||
if (width % 2 == 0){
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 水壶 " + key + " 的浇灌宽度必须为奇数!</red>");
|
||||
return;
|
||||
}
|
||||
WateringCan wateringCan = new WateringCan(config.getInt("water-can." + key + ".max"), width, config.getInt("water-can." + key + ".length"));
|
||||
CANS.put(key, wateringCan);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 水壶 " + key + " 与ItemsAdder物品ID不一致</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SPRINKLERS.clear();
|
||||
if (config.contains("sprinkler")){
|
||||
config.getConfigurationSection("sprinkler").getKeys(false).forEach(key -> {
|
||||
if (key.equals(StringUtils.split(config.getString("sprinkler." + key + ".3Ditem"),":")[1])){
|
||||
Sprinkler sprinklerData = new Sprinkler(config.getInt("sprinkler." + key + ".range"), config.getInt("sprinkler." + key + ".max-water"));
|
||||
sprinklerData.setNamespacedID_2(config.getString("sprinkler." + key + ".3Ditem"));
|
||||
String twoD = config.getString("sprinkler." + key + ".2Ditem");
|
||||
sprinklerData.setNamespacedID_1(twoD);
|
||||
SPRINKLERS.put(key, sprinklerData);
|
||||
SPRINKLERS.put(StringUtils.split(twoD,":")[1], sprinklerData);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 洒水器 " + key + " 与ItemsAdder物品ID不一致</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Season{
|
||||
|
||||
public static boolean enable;
|
||||
public static boolean greenhouse;
|
||||
public static boolean seasonChange;
|
||||
public static int range;
|
||||
public static int duration;
|
||||
|
||||
public static void loadSeason(){
|
||||
YamlConfiguration config = getConfig("season.yml");
|
||||
|
||||
enable = config.getBoolean("season.enable",false);
|
||||
if (enable){
|
||||
greenhouse = config.getBoolean("season.greenhouse.enable",false);
|
||||
if (greenhouse) {
|
||||
range = config.getInt("season.greenhouse.range",7);
|
||||
}
|
||||
seasonChange = config.getBoolean("season.auto-season-change.enable",false);
|
||||
if (seasonChange) {
|
||||
duration = config.getInt("season.auto-season-change.duration",28);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Message{
|
||||
|
||||
public static String prefix;
|
||||
public static String reload;
|
||||
public static String lackArgs;
|
||||
public static String noPerm;
|
||||
public static String spring;
|
||||
public static String summer;
|
||||
public static String autumn;
|
||||
public static String winter;
|
||||
public static String sprinkler_limit;
|
||||
public static String crop_limit;
|
||||
public static String not_configed;
|
||||
public static String badY;
|
||||
public static String badBiome;
|
||||
public static String badWorld;
|
||||
public static String badPerm;
|
||||
public static String badSeason;
|
||||
public static String forceGrow;
|
||||
public static String forceWater;
|
||||
public static String backUp;
|
||||
public static String setSeason;
|
||||
public static String wrongArgs;
|
||||
public static String forceSave;
|
||||
public static boolean hasCropInfo;
|
||||
public static boolean hasSprinklerInfo;
|
||||
public static int cropTime;
|
||||
public static int sprinklerTime;
|
||||
public static String cropText;
|
||||
public static String sprinklerLeft;
|
||||
public static String sprinklerFull;
|
||||
public static String sprinklerEmpty;
|
||||
public static String sprinklerRight;
|
||||
public static double cropOffset;
|
||||
public static double sprinklerOffset;
|
||||
|
||||
public static void loadMessage(){
|
||||
YamlConfiguration config = getConfig("messages.yml");
|
||||
prefix = config.getString("messages.prefix");
|
||||
reload = config.getString("messages.reload");
|
||||
lackArgs = config.getString("messages.lack-args");
|
||||
noPerm = config.getString("messages.no-perm");
|
||||
spring = config.getString("messages.spring");
|
||||
summer = config.getString("messages.summer");
|
||||
autumn = config.getString("messages.autumn");
|
||||
winter = config.getString("messages.winter");
|
||||
sprinkler_limit = config.getString("messages.sprinkler-limit");
|
||||
crop_limit = config.getString("messages.crop-limit");
|
||||
not_configed = config.getString("messages.not-configed");
|
||||
badY = config.getString("messages.bad-Y");
|
||||
badBiome = config.getString("messages.bad-biome");
|
||||
badWorld = config.getString("messages.bad-world");
|
||||
badPerm = config.getString("messages.bad-perm");
|
||||
badSeason = config.getString("messages.bad-season");
|
||||
forceGrow = config.getString("messages.force-grow");
|
||||
forceWater = config.getString("messages.force-water");
|
||||
backUp = config.getString("messages.back-up");
|
||||
setSeason = config.getString("messages.set-season");
|
||||
wrongArgs = config.getString("messages.wrong-args");
|
||||
forceSave = config.getString("messages.force-save");
|
||||
|
||||
hasCropInfo = config.getBoolean("hologram.grow-info.enable");
|
||||
if (hasCropInfo){
|
||||
cropTime = config.getInt("hologram.grow-info.duration");
|
||||
cropText = config.getString("hologram.grow-info.text");
|
||||
cropOffset = config.getDouble("hologram.grow-info.y-offset");
|
||||
}
|
||||
hasSprinklerInfo = config.getBoolean("hologram.sprinkler-info.enable");
|
||||
if (hasSprinklerInfo){
|
||||
sprinklerTime = config.getInt("hologram.sprinkler-info.duration");
|
||||
sprinklerLeft = config.getString("hologram.sprinkler-info.left");
|
||||
sprinklerFull = config.getString("hologram.sprinkler-info.full");
|
||||
sprinklerEmpty = config.getString("hologram.sprinkler-info.empty");
|
||||
sprinklerRight = config.getString("hologram.sprinkler-info.right");
|
||||
sprinklerOffset = config.getDouble("hologram.sprinkler-info.y-offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void cropLoad(){
|
||||
CROPS.clear();
|
||||
YamlConfiguration config = getConfig("crops.yml");
|
||||
Set<String> keys = config.getConfigurationSection("crops").getKeys(false);
|
||||
keys.forEach(key -> {
|
||||
CropInstance cropInstance;
|
||||
if (config.contains("crops." + key + ".amount")){
|
||||
String[] split = StringUtils.split(config.getString("crops." + key + ".amount"),"~");
|
||||
cropInstance = new CropInstance(Integer.parseInt(split[0]),Integer.parseInt(split[1]));
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 未设置农作物 " + key +" 的产物数量!</red>");
|
||||
return;
|
||||
}
|
||||
if (config.contains("crops." + key + ".gigantic")){
|
||||
cropInstance.setGiant(config.getString("crops." + key + ".gigantic.block"));
|
||||
cropInstance.setGiantChance(config.getDouble("crops." + key + ".gigantic.chance"));
|
||||
}
|
||||
if (Season.enable && config.contains("crops." + key + ".season")){
|
||||
cropInstance.setSeasons(config.getStringList("crops." + key + ".season"));
|
||||
}
|
||||
if (config.contains("crops." + key + ".return")){
|
||||
cropInstance.setReturnStage(config.getString("crops." + key + ".return"));
|
||||
}
|
||||
if (config.contains("crops." + key + ".requirements")){
|
||||
List<Requirement> requirements = new ArrayList<>();
|
||||
config.getConfigurationSection("crops." + key + ".requirements").getValues(false).forEach((requirement, value) -> {
|
||||
switch (requirement){
|
||||
case "world" -> requirements.add(new net.momirealms.customcrops.requirements.World((List<String>) value));
|
||||
case "yPos" -> requirements.add(new YPos((List<String>) value));
|
||||
case "biome" -> requirements.add(new Biome((List<String>) value));
|
||||
case "permission" -> requirements.add(new Permission((String) value));
|
||||
}
|
||||
});
|
||||
cropInstance.setRequirements(requirements);
|
||||
}
|
||||
if (Config.quality){
|
||||
cropInstance.setQuality_1(config.getString("crops." + key + ".quality.1"));
|
||||
cropInstance.setQuality_2(config.getString("crops." + key + ".quality.2"));
|
||||
cropInstance.setQuality_3(config.getString("crops." + key + ".quality.3"));
|
||||
}
|
||||
CROPS.put(key, cropInstance);
|
||||
});
|
||||
}
|
||||
|
||||
public static void fertilizerLoad(){
|
||||
FERTILIZERS.clear();
|
||||
YamlConfiguration config = getConfig("fertilizer.yml");
|
||||
if (config.contains("加速肥料")){
|
||||
config.getConfigurationSection("加速肥料").getKeys(false).forEach(key -> {
|
||||
if (StringUtils.split(config.getString("加速肥料." + key + ".item"), ":")[1].equals(key)){
|
||||
SpeedGrow speedGrow = new SpeedGrow(key, config.getInt("加速肥料." + key + ".times"), config.getDouble("加速肥料." + key + ".chance"), config.getBoolean("加速肥料." + key + ".before-plant"));
|
||||
speedGrow.setName(config.getString("加速肥料." + key + ".name"));
|
||||
FERTILIZERS.put(key, speedGrow);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 肥料 " + key + " 与ItemsAdder物品ID不一致</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
if (config.contains("保湿肥料")){
|
||||
config.getConfigurationSection("保湿肥料").getKeys(false).forEach(key -> {
|
||||
if (StringUtils.split(config.getString("保湿肥料." + key + ".item"), ":")[1].equals(key)){
|
||||
RetainingSoil retainingSoil = new RetainingSoil(key, config.getInt("保湿肥料." + key + ".times"), config.getDouble("保湿肥料." + key + ".chance"), config.getBoolean("保湿肥料." + key + ".before-plant"));
|
||||
retainingSoil.setName(config.getString("保湿肥料." + key + ".name"));
|
||||
FERTILIZERS.put(key, retainingSoil);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 肥料 " + key + " 与ItemsAdder物品ID不一致</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
if (config.contains("品质肥料")){
|
||||
config.getConfigurationSection("品质肥料").getKeys(false).forEach(key -> {
|
||||
if (StringUtils.split(config.getString("品质肥料." + key + ".item"), ":")[1].equals(key)){
|
||||
String[] split = StringUtils.split(config.getString("品质肥料." + key + ".chance"), "/");
|
||||
int[] weight = new int[3];
|
||||
weight[0] = Integer.parseInt(split[0]);
|
||||
weight[1] = Integer.parseInt(split[1]);
|
||||
weight[2] = Integer.parseInt(split[2]);
|
||||
QualityCrop qualityCrop = new QualityCrop(key, config.getInt("品质肥料." + key + ".times"), weight, config.getBoolean("品质肥料." + key + ".before-plant"));
|
||||
qualityCrop.setName(config.getString("品质肥料." + key + ".name"));
|
||||
FERTILIZERS.put(key, qualityCrop);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 肥料 " + key + " 与ItemsAdder物品ID不一致</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +1,120 @@
|
||||
package net.momirealms.customcrops;
|
||||
|
||||
import net.momirealms.customcrops.commands.CommandHandler;
|
||||
import net.momirealms.customcrops.commands.CommandTabComplete;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.momirealms.customcrops.commands.Executor;
|
||||
import net.momirealms.customcrops.commands.Completer;
|
||||
import net.momirealms.customcrops.datamanager.*;
|
||||
import net.momirealms.customcrops.listener.BreakCrops;
|
||||
import net.momirealms.customcrops.listener.BreakBlock;
|
||||
import net.momirealms.customcrops.listener.InteractEntity;
|
||||
import net.momirealms.customcrops.listener.ItemSpawn;
|
||||
import net.momirealms.customcrops.listener.RightClick;
|
||||
import net.momirealms.customcrops.timer.CropTimer;
|
||||
import net.momirealms.customcrops.listener.BreakCustomBlock;
|
||||
import net.momirealms.customcrops.listener.RightClickBlock;
|
||||
import net.momirealms.customcrops.listener.RightClickCustomBlock;
|
||||
import net.momirealms.customcrops.timer.CropTimerAsync;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.utils.BackUp;
|
||||
import net.momirealms.customcrops.utils.HoloUtil;
|
||||
import net.momirealms.customcrops.utils.Placeholders;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class CustomCrops extends JavaPlugin {
|
||||
|
||||
public static JavaPlugin instance;
|
||||
public static CropTimer timer;
|
||||
public static BukkitAudiences adventure;
|
||||
private CropTimer cropTimer;
|
||||
private CropTimerAsync cropTimerAsync;
|
||||
private CropManager cropManager;
|
||||
private SprinklerManager sprinklerManager;
|
||||
private SeasonManager seasonManager;
|
||||
private PotManager potManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
instance = this;
|
||||
adventure = BukkitAudiences.create(this);
|
||||
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>Running on " + Bukkit.getVersion());
|
||||
|
||||
//加载配置文件
|
||||
ConfigManager.Config.ReloadConfig();
|
||||
ConfigReader.ReloadConfig();
|
||||
|
||||
//PAPI
|
||||
if(Bukkit.getPluginManager().getPlugin("PlaceHolderAPI") != null){
|
||||
new Placeholders().register();
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>检测到 <gold>PlaceHolderAPI <color:#FFEBCD>已启用变量!");
|
||||
}
|
||||
|
||||
//指令注册
|
||||
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setExecutor(new CommandHandler());
|
||||
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setTabCompleter(new CommandTabComplete());
|
||||
Bukkit.getPluginManager().registerEvents(new RightClickCustomBlock(),this);
|
||||
Bukkit.getPluginManager().registerEvents(new BreakCustomBlock(),this);
|
||||
Bukkit.getPluginManager().registerEvents(new RightClickBlock(),this);
|
||||
Bukkit.getPluginManager().registerEvents(new BreakCrops(),this);
|
||||
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setExecutor(new Executor(this));
|
||||
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setTabCompleter(new Completer());
|
||||
|
||||
//开始计时任务
|
||||
CustomCrops.timer = new CropTimer();
|
||||
//注册事件
|
||||
Bukkit.getPluginManager().registerEvents(new ItemSpawn(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new RightClick(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new BreakBlock(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new InteractEntity(this), this);
|
||||
|
||||
//新建data文件
|
||||
File crop_file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||
File sprinkler_file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||
if(!crop_file.exists()){
|
||||
try {
|
||||
crop_file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 农作物数据文件生成失败!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
if(!sprinkler_file.exists()){
|
||||
try {
|
||||
sprinkler_file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 洒水器数据文件生成失败!",Bukkit.getConsoleSender());
|
||||
}
|
||||
//开始计时器
|
||||
if(ConfigReader.Config.asyncCheck){
|
||||
this.cropTimerAsync = new CropTimerAsync(this);
|
||||
}else {
|
||||
this.cropTimer = new CropTimer(this);
|
||||
}
|
||||
|
||||
//载入data数据
|
||||
CropManager.loadData();
|
||||
SprinklerManager.loadData();
|
||||
|
||||
//检测papi依赖
|
||||
if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null){
|
||||
new Placeholders(this).register();
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7检测到 &aPlaceHolderAPI &7已启用季节变量!",Bukkit.getConsoleSender());
|
||||
//载入数据
|
||||
if (ConfigReader.Season.enable){
|
||||
this.seasonManager = new SeasonManager(this);
|
||||
this.seasonManager.loadData();
|
||||
}
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7自定义农作物插件已启用!作者:小默米 QQ:3266959688",Bukkit.getConsoleSender());
|
||||
this.cropManager = new CropManager(this);
|
||||
this.cropManager.loadData();
|
||||
this.sprinklerManager = new SprinklerManager(this);
|
||||
this.sprinklerManager.loadData();
|
||||
this.potManager = new PotManager(this);
|
||||
this.potManager.loadData();
|
||||
|
||||
//启动完成
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>插件已加载!作者:小默米 QQ:3266959688");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
//关闭定时任务
|
||||
if (CustomCrops.timer != null) {
|
||||
CropTimer.stopTimer(CustomCrops.timer.getTaskID());
|
||||
|
||||
//保存数据
|
||||
this.cropManager.saveData();
|
||||
this.sprinklerManager.saveData();
|
||||
this.potManager.saveData();
|
||||
if (ConfigReader.Season.enable && !ConfigReader.Season.seasonChange){
|
||||
this.seasonManager.saveData();
|
||||
}
|
||||
|
||||
//保存缓存中的数据
|
||||
CropManager.saveData();
|
||||
SprinklerManager.saveData();
|
||||
//清除悬浮展示实体
|
||||
HoloUtil.cache.keySet().forEach(player -> {
|
||||
HoloUtil.cache.get(player).remove();
|
||||
});
|
||||
|
||||
//备份
|
||||
//关闭计时器
|
||||
if (cropTimer != null) {
|
||||
this.cropTimer.stopTimer(cropTimer.getTaskID());
|
||||
}
|
||||
if (cropTimerAsync != null){
|
||||
this.cropTimerAsync.stopTimer(cropTimerAsync.getTaskID());
|
||||
}
|
||||
|
||||
//备份数据
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>插件数据自动备份中...");
|
||||
BackUp.backUpData();
|
||||
MessageManager.consoleMessage(("&#ccfbff-#ef96c5&[CustomCrops] &7自定义农作物插件已卸载!作者:小默米 QQ:3266959688"),Bukkit.getConsoleSender());
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>备份已完成!");
|
||||
|
||||
//卸载完成
|
||||
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>插件已卸载!作者:小默米 QQ:3266959688");
|
||||
}
|
||||
|
||||
public CropManager getCropManager() { return this.cropManager; }
|
||||
public SprinklerManager getSprinklerManager() { return sprinklerManager; }
|
||||
public SeasonManager getSeasonManager() { return seasonManager; }
|
||||
public PotManager getPotManager() { return potManager; }
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package net.momirealms.customcrops.commands;
|
||||
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.datamanager.MessageManager;
|
||||
import net.momirealms.customcrops.datamanager.BackUp;
|
||||
import net.momirealms.customcrops.datamanager.CropManager;
|
||||
import net.momirealms.customcrops.datamanager.NextSeason;
|
||||
import net.momirealms.customcrops.datamanager.SprinklerManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
public class CommandHandler implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
@ParametersAreNonnullByDefault
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if(args.length<1) return true;
|
||||
//重载插件
|
||||
if(args[0].equalsIgnoreCase("reload")){
|
||||
|
||||
ConfigManager.Config.ReloadConfig();
|
||||
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.reload, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.reload, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//设置季节
|
||||
if(args[0].equalsIgnoreCase("setseason")){
|
||||
if(args.length<2) return true;
|
||||
if(ConfigManager.Config.season){
|
||||
|
||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||
config.set("current-season", args[1]);
|
||||
CustomCrops.instance.saveConfig();
|
||||
ConfigManager.Config.current = args[1];
|
||||
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_set.replace("{Season}",args[1])
|
||||
.replace("spring", ConfigManager.Config.spring)
|
||||
.replace("summer", ConfigManager.Config.summer)
|
||||
.replace("autumn", ConfigManager.Config.autumn)
|
||||
.replace("winter", ConfigManager.Config.winter), (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(config.getString("messages.prefix") + ConfigManager.Config.season_set.replace("{Season}",args[1])
|
||||
.replace("spring", ConfigManager.Config.spring)
|
||||
.replace("summer", ConfigManager.Config.summer)
|
||||
.replace("autumn", ConfigManager.Config.autumn)
|
||||
.replace("winter", ConfigManager.Config.winter), Bukkit.getConsoleSender());
|
||||
}
|
||||
|
||||
}else{
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_disabled, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.season_disabled, Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//强制保存
|
||||
if(args[0].equalsIgnoreCase("forcesave")){
|
||||
CropManager.saveData();
|
||||
SprinklerManager.saveData();
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_save, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_save, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//强制生长
|
||||
if(args[0].equalsIgnoreCase("forcegrow")){
|
||||
if(args.length<2) return true;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance, () -> CropManager.CropGrow(args[1]));
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_grow, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_grow, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//强制洒水
|
||||
if(args[0].equalsIgnoreCase("forcewater")){
|
||||
if(args.length<2) return true;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance, () -> SprinklerManager.SprinklerWork(args[1]));
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_water, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.force_water, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("backup")){
|
||||
BackUp.backUpData();
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.backup, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.backup, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("nextseason")){
|
||||
NextSeason.changeSeason();
|
||||
if(sender instanceof Player){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.nextSeason, (Player) sender);
|
||||
}else {
|
||||
MessageManager.consoleMessage(ConfigManager.Config.prefix + ConfigManager.Config.nextSeason, Bukkit.getConsoleSender());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package net.momirealms.customcrops.commands;
|
||||
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandTabComplete implements TabCompleter {
|
||||
|
||||
@Override
|
||||
@ParametersAreNonnullByDefault
|
||||
public @Nullable List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList("backup" , "forcegrow", "forcesave", "forcewater", "reload", "setseason" , "nextseason");
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("setseason")){
|
||||
return Arrays.asList("spring","summer","autumn","winter");
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("forcegrow") || args[0].equalsIgnoreCase("forcewater")){
|
||||
return ConfigManager.Config.worlds;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.momirealms.customcrops.commands;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Completer implements TabCompleter {
|
||||
|
||||
@Override
|
||||
@ParametersAreNonnullByDefault
|
||||
public @Nullable List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (!(sender.isOp() || sender.hasPermission("customcrops.admin"))){
|
||||
return null;
|
||||
}
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList("backup", "forcegrow", "forcesave", "forcewater", "reload", "setseason");
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("setseason") && args.length == 2){
|
||||
return ConfigReader.Config.worldNames;
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("forcesave") && args.length == 2){
|
||||
if (ConfigReader.Season.enable){
|
||||
if (ConfigReader.Season.seasonChange){
|
||||
return Arrays.asList("all","crop","pot","sprinkler");
|
||||
}else{
|
||||
return Arrays.asList("all","crop","pot","season","sprinkler");
|
||||
}
|
||||
}else {
|
||||
return Arrays.asList("all","crop","pot","sprinkler");
|
||||
}
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("setseason") && args.length == 3){
|
||||
return Arrays.asList("spring","summer","autumn","winter");
|
||||
}
|
||||
if(args[0].equalsIgnoreCase("forcegrow") || args[0].equalsIgnoreCase("forcewater")){
|
||||
return ConfigReader.Config.worldNames;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
164
src/main/java/net/momirealms/customcrops/commands/Executor.java
Normal file
164
src/main/java/net/momirealms/customcrops/commands/Executor.java
Normal file
@@ -0,0 +1,164 @@
|
||||
package net.momirealms.customcrops.commands;
|
||||
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.utils.BackUp;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
public class Executor implements CommandExecutor {
|
||||
|
||||
private final CustomCrops plugin;
|
||||
|
||||
public Executor(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ParametersAreNonnullByDefault
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
//权限不足
|
||||
if (!(sender.hasPermission("customcrops.admin") || sender.isOp())){
|
||||
AdventureManager.playerMessage((Player) sender, ConfigReader.Message.prefix + ConfigReader.Message.noPerm);
|
||||
return true;
|
||||
}
|
||||
//参数不足
|
||||
if (args.length < 1) {
|
||||
lackArgs(sender);
|
||||
return true;
|
||||
}
|
||||
switch (args[0]){
|
||||
case "reload" -> {
|
||||
long time = System.currentTimeMillis();
|
||||
ConfigReader.ReloadConfig();
|
||||
if(sender instanceof Player){
|
||||
AdventureManager.playerMessage((Player) sender,ConfigReader.Message.prefix + ConfigReader.Message.reload.replace("{time}", String.valueOf(System.currentTimeMillis() - time)));
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.reload.replace("{time}", String.valueOf(System.currentTimeMillis() - time)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "forcegrow" -> {
|
||||
if (args.length < 2) {
|
||||
lackArgs(sender);
|
||||
return true;
|
||||
}
|
||||
plugin.getCropManager().cropGrow(args[1]);
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.forceGrow.replace("{world}",args[1]));
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.forceGrow.replace("{world}",args[1]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "forcewater" -> {
|
||||
if (args.length < 2) {
|
||||
lackArgs(sender);
|
||||
return true;
|
||||
}
|
||||
plugin.getSprinklerManager().sprinklerWork(args[1]);
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.forceWater.replace("{world}",args[1]));
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.forceWater.replace("{world}",args[1]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "forcesave" -> {
|
||||
if (args.length < 2) {
|
||||
lackArgs(sender);
|
||||
return true;
|
||||
}
|
||||
switch (args[1]){
|
||||
case "all" -> {
|
||||
plugin.getSprinklerManager().updateData();
|
||||
plugin.getSprinklerManager().saveData();
|
||||
if (ConfigReader.Season.enable && !ConfigReader.Season.seasonChange){
|
||||
plugin.getSeasonManager().saveData();
|
||||
}
|
||||
plugin.getCropManager().updateData();
|
||||
plugin.getCropManager().saveData();
|
||||
plugin.getPotManager().saveData();
|
||||
forceSave(sender);
|
||||
}
|
||||
case "crop" -> {
|
||||
plugin.getCropManager().updateData();
|
||||
plugin.getCropManager().saveData();
|
||||
forceSave(sender);
|
||||
}
|
||||
case "pot" -> {
|
||||
plugin.getPotManager().saveData();
|
||||
forceSave(sender);
|
||||
}
|
||||
case "season" -> {
|
||||
plugin.getSeasonManager().saveData();
|
||||
forceSave(sender);
|
||||
}
|
||||
case "sprinkler" -> {
|
||||
plugin.getSprinklerManager().updateData();
|
||||
plugin.getSprinklerManager().saveData();
|
||||
forceSave(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
case "backup" -> {
|
||||
BackUp.backUpData();
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.backUp);
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.backUp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "setseason" -> {
|
||||
if (args.length < 3) {
|
||||
lackArgs(sender);
|
||||
return true;
|
||||
}
|
||||
if (plugin.getSeasonManager().setSeason(args[1], args[2])){
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.setSeason.replace("{world}",args[1]).replace("{season}",args[2]));
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.setSeason.replace("{world}",args[1]).replace("{season}",args[2]));
|
||||
}
|
||||
}else {
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.wrongArgs);
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.wrongArgs);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default -> {
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,"");
|
||||
}else {
|
||||
AdventureManager.consoleMessage("");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void lackArgs(CommandSender sender){
|
||||
if (sender instanceof Player){
|
||||
AdventureManager.playerMessage((Player) sender,ConfigReader.Message.prefix + ConfigReader.Message.lackArgs);
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.lackArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private void forceSave(CommandSender sender){
|
||||
if (sender instanceof Player player){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.forceSave);
|
||||
}else {
|
||||
AdventureManager.consoleMessage(ConfigReader.Message.prefix + ConfigReader.Message.forceSave);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.utils.Crop;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
public static HashMap<String, Crop> CONFIG;
|
||||
static {
|
||||
CONFIG = new HashMap<>();
|
||||
}
|
||||
|
||||
public static class Config{
|
||||
|
||||
public static boolean res;
|
||||
public static boolean wg;
|
||||
public static boolean king;
|
||||
public static boolean gd;
|
||||
public static boolean season;
|
||||
public static boolean need_water;
|
||||
public static boolean greenhouse;
|
||||
public static boolean limit;
|
||||
public static boolean log_time;
|
||||
|
||||
public static List<String> worlds;
|
||||
public static List<Long> cropGrowTimeList;
|
||||
public static List<Long> sprinklerWorkTimeList;
|
||||
|
||||
public static String current;
|
||||
public static String prefix;
|
||||
public static String bad_place;
|
||||
public static String reload;
|
||||
public static String force_save;
|
||||
public static String nextSeason;
|
||||
public static String no_such_seed;
|
||||
public static String wrong_season;
|
||||
public static String season_set;
|
||||
public static String season_disabled;
|
||||
public static String force_grow;
|
||||
public static String force_water;
|
||||
public static String limit_crop;
|
||||
public static String limit_sprinkler;
|
||||
public static String backup;
|
||||
public static String spring;
|
||||
public static String summer;
|
||||
public static String autumn;
|
||||
public static String winter;
|
||||
public static String can_full;
|
||||
public static String pot;
|
||||
public static String watered_pot;
|
||||
public static String watering_can_1;
|
||||
public static String watering_can_2;
|
||||
public static String watering_can_3;
|
||||
public static String glass;
|
||||
public static String sprinkler_1;
|
||||
public static String sprinkler_2;
|
||||
public static String sprinkler_1i;
|
||||
public static String sprinkler_2i;
|
||||
public static String dead;
|
||||
public static String success;
|
||||
public static String failure;
|
||||
|
||||
public static double bone_chance;
|
||||
|
||||
public static int range;
|
||||
public static int maxh;
|
||||
public static int minh;
|
||||
public static int max_crop;
|
||||
public static int max_sprinkler;
|
||||
|
||||
public static void ReloadConfig(){
|
||||
CustomCrops.instance.saveDefaultConfig();
|
||||
CustomCrops.instance.reloadConfig();
|
||||
FileConfiguration configuration = CustomCrops.instance.getConfig();
|
||||
//处理配置
|
||||
Config.res = configuration.getBoolean("config.integration.residence",false);
|
||||
Config.king = configuration.getBoolean("config.integration.kingdomsX",false);
|
||||
Config.wg = configuration.getBoolean("config.integration.worldguard",false);
|
||||
Config.gd = configuration.getBoolean("config.integration.griefdefender",false);
|
||||
|
||||
if(res){
|
||||
if(Bukkit.getPluginManager().getPlugin("Residence") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件Residence!");
|
||||
res = false;
|
||||
}else {
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7检测到 &aResidence &7已启用领地保护!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
if(king){
|
||||
if(Bukkit.getPluginManager().getPlugin("Kingdoms") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件KingdomsX!");
|
||||
king = false;
|
||||
}else {
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7检测到 &aKingdomsX &7已启用领地保护!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
if(wg){
|
||||
if(Bukkit.getPluginManager().getPlugin("WorldGuard") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件WorldGuard!");
|
||||
wg = false;
|
||||
}else {
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7检测到 &aWorldGuard &7已启用区域保护!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
if(gd){
|
||||
if(Bukkit.getPluginManager().getPlugin("GriefDefender") == null){
|
||||
CustomCrops.instance.getLogger().warning("未检测到插件GriefDefender!");
|
||||
gd = false;
|
||||
}else {
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7检测到 &aGriefDefender &7已启用领地保护!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
|
||||
Config.season = configuration.getBoolean("enable-season");
|
||||
Config.need_water = configuration.getBoolean("config.bone-meal-consume-water");
|
||||
Config.greenhouse = configuration.getBoolean("config.enable-greenhouse");
|
||||
Config.limit = configuration.getBoolean("config.enable-limit");
|
||||
Config.log_time = configuration.getBoolean("config.log-time-consume", false);
|
||||
|
||||
Config.bone_chance = configuration.getDouble("config.bone-meal-chance");
|
||||
|
||||
Config.range = configuration.getInt("config.greenhouse-range");
|
||||
Config.maxh = configuration.getInt("config.height.max");
|
||||
Config.minh = configuration.getInt("config.height.min");
|
||||
Config.max_crop = configuration.getInt("config.max-crops");
|
||||
Config.max_sprinkler = configuration.getInt("config.max-sprinklers");
|
||||
|
||||
Config.current = configuration.getString("current-season");
|
||||
Config.pot = configuration.getString("config.pot");
|
||||
Config.watered_pot = configuration.getString("config.watered-pot");
|
||||
Config.watering_can_1 = configuration.getString("config.watering-can-1");
|
||||
Config.watering_can_2 = configuration.getString("config.watering-can-2");
|
||||
Config.watering_can_3 = configuration.getString("config.watering-can-3");
|
||||
Config.glass = configuration.getString("config.greenhouse-glass");
|
||||
Config.sprinkler_1 = configuration.getString("config.sprinkler-1");
|
||||
Config.sprinkler_2 = configuration.getString("config.sprinkler-2");
|
||||
Config.sprinkler_1i = configuration.getString("config.sprinkler-1-item");
|
||||
Config.sprinkler_2i = configuration.getString("config.sprinkler-2-item");
|
||||
Config.dead = configuration.getString("config.dead-crop");
|
||||
Config.success = configuration.getString("config.particle.success");
|
||||
Config.failure = configuration.getString("config.particle.failure");
|
||||
|
||||
Config.worlds = configuration.getStringList("config.whitelist-worlds");
|
||||
Config.cropGrowTimeList = configuration.getLongList("config.grow-time");
|
||||
Config.sprinklerWorkTimeList = configuration.getLongList("config.sprinkler-time");
|
||||
|
||||
//处理消息
|
||||
Config.prefix = configuration.getString("messages.prefix");
|
||||
Config.bad_place = configuration.getString("messages.not-a-good-place");
|
||||
Config.reload = configuration.getString("messages.reload");
|
||||
Config.force_save = configuration.getString("messages.force-save");
|
||||
Config.nextSeason = configuration.getString("messages.nextseason");
|
||||
Config.no_such_seed = configuration.getString("messages.no-such-seed");
|
||||
Config.wrong_season = configuration.getString("messages.wrong-season");
|
||||
Config.season_set = configuration.getString("messages.season-set");
|
||||
Config.season_disabled = configuration.getString("messages.season-disabled");
|
||||
Config.force_grow = configuration.getString("messages.force-grow");
|
||||
Config.force_water = configuration.getString("messages.force-water");
|
||||
Config.limit_crop = configuration.getString("messages.reach-limit-crop");
|
||||
Config.limit_sprinkler = configuration.getString("messages.reach-limit-sprinkler");
|
||||
Config.can_full = configuration.getString("messages.can-full");
|
||||
Config.backup = configuration.getString("messages.backup");
|
||||
Config.spring = configuration.getString("messages.spring");
|
||||
Config.summer = configuration.getString("messages.summer");
|
||||
Config.autumn = configuration.getString("messages.autumn");
|
||||
Config.winter = configuration.getString("messages.winter");
|
||||
|
||||
cropLoad();
|
||||
}
|
||||
|
||||
/*
|
||||
根据文件名获取配置文件
|
||||
*/
|
||||
public static YamlConfiguration getConfig(String configName) {
|
||||
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), configName);
|
||||
//文件不存在则生成默认配置
|
||||
if (!file.exists()) {
|
||||
CustomCrops.instance.saveResource(configName, false);
|
||||
}
|
||||
return YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
/*
|
||||
加载农作物数据
|
||||
*/
|
||||
public static void cropLoad(){
|
||||
try {
|
||||
CONFIG.clear();
|
||||
YamlConfiguration cropConfig = getConfig("crops.yml");
|
||||
Set<String> keys = cropConfig.getConfigurationSection("crops").getKeys(false);
|
||||
keys.forEach(key -> {
|
||||
if(cropConfig.getConfigurationSection("crops."+key).contains("grow-chance")){
|
||||
double chance = cropConfig.getDouble("crops."+key+".grow-chance");
|
||||
Crop crop = new Crop(key, chance);
|
||||
if(cropConfig.getConfigurationSection("crops."+key).contains("return")){
|
||||
crop.setWillReturn(true);
|
||||
crop.setReturnStage(cropConfig.getString("crops."+key+".return"));
|
||||
}else {
|
||||
crop.setWillReturn(false);
|
||||
}
|
||||
if(Config.season){
|
||||
if(cropConfig.getConfigurationSection("crops."+key).contains("season")){
|
||||
crop.setSeasons(StringUtils.split( cropConfig.getString("crops."+key+".season"), ","));
|
||||
}else {
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 错误!在启用季节模式的情况下未设置农作物 &f"+ key +" &c的生长季节!", Bukkit.getConsoleSender());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(cropConfig.getConfigurationSection("crops."+key).contains("gigantic")){
|
||||
crop.setWillGiant(true);
|
||||
crop.setGiant(cropConfig.getString("crops."+key+".gigantic"));
|
||||
if(cropConfig.getConfigurationSection("crops."+key).contains("gigantic-chance")){
|
||||
crop.setGiantChance(cropConfig.getDouble("crops."+key+".gigantic-chance"));
|
||||
}else {
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 错误!未设置农作物 &f"+ key +" &c的巨大化概率!", Bukkit.getConsoleSender());
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
crop.setWillGiant(false);
|
||||
}
|
||||
CONFIG.put(key, crop);
|
||||
}else {
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 错误!未设置农作物 &f"+ key +" &c的生长概率!", Bukkit.getConsoleSender());
|
||||
}
|
||||
});
|
||||
if(keys.size() == CONFIG.size()){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7成功载入 &a" + CONFIG.size() + " &7种农作物", Bukkit.getConsoleSender());
|
||||
}else {
|
||||
MessageManager.consoleMessage("&c[CustomCrops] crops.yml配置存在错误,请根据上述提示仔细检查!", Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("crops.yml加载失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,249 +1,236 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import net.momirealms.customcrops.fertilizer.QualityCrop;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.utils.Crop;
|
||||
import net.momirealms.customcrops.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.fertilizer.RetainingSoil;
|
||||
import net.momirealms.customcrops.fertilizer.SpeedGrow;
|
||||
import net.momirealms.customcrops.utils.CropInstance;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class CropManager {
|
||||
|
||||
public static ConcurrentHashMap<Location, String> CROPS;
|
||||
/*
|
||||
开服的时候将文件的数据读入
|
||||
*/
|
||||
public static void loadData() {
|
||||
private YamlConfiguration data;
|
||||
private final CustomCrops plugin;
|
||||
public static ConcurrentHashMap<Location, String> Cache = new ConcurrentHashMap<>();
|
||||
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
public CropManager(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
CROPS = new ConcurrentHashMap<>();
|
||||
|
||||
for (String world : ConfigManager.Config.worlds) {
|
||||
//如果数据文件中有相应世界才进行读取
|
||||
if(data.contains(world)){
|
||||
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
||||
Location tempLoc = new Location(Bukkit.getWorld(world), Integer.parseInt(coordinate.split(",")[0]), Integer.parseInt(coordinate.split(",")[1]), Integer.parseInt(coordinate.split(",")[2]));
|
||||
String cropName = data.getString(world + "." + coordinate);
|
||||
CROPS.put(tempLoc, cropName);
|
||||
}
|
||||
//载入数据
|
||||
public void loadData() {
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "crop.yml");
|
||||
if(!file.exists()){
|
||||
try {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 农作物数据文件生成失败!</red>");
|
||||
}
|
||||
}
|
||||
this.data = YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
/*
|
||||
保存数据
|
||||
*/
|
||||
public static void saveData(){
|
||||
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||
FileConfiguration data;
|
||||
data = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
Set<Map.Entry<Location, String>> en = CROPS.entrySet();
|
||||
for(Map.Entry<Location, String> entry : en){
|
||||
Location loc = entry.getKey();
|
||||
data.set(loc.getWorld().getName()+"."+ loc.getBlockX() + "," + loc.getBlockY()+ ","+loc.getBlockZ(), entry.getValue());
|
||||
}
|
||||
try {
|
||||
data.save(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("农作物数据保存出错");
|
||||
}
|
||||
}
|
||||
/*
|
||||
生长部分
|
||||
*/
|
||||
public static void CropGrow(String worldName) {
|
||||
/*
|
||||
阶段1:更新数据
|
||||
*/
|
||||
long start1 = System.currentTimeMillis();
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
Set<Map.Entry<Location, String>> en = CROPS.entrySet();
|
||||
for(Map.Entry<Location, String> entry : en){
|
||||
Location key = entry.getKey();
|
||||
data.set(key.getWorld().getName() + "." + key.getBlockX() + "," + key.getBlockY()+ ","+ key.getBlockZ(), entry.getValue());
|
||||
}
|
||||
long finish1 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7农作物数据更新耗时&a" + (finish1 - start1) + "&fms",Bukkit.getConsoleSender());
|
||||
}
|
||||
/*
|
||||
阶段2:清理数据内无效的农作物并让有效农作物生长
|
||||
*/
|
||||
long start2 = System.currentTimeMillis();
|
||||
if(data.contains(worldName)){
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{
|
||||
String[] coordinate = StringUtils.split(key,",");
|
||||
//先判断区块是否加载,未加载则不进行下一步计算
|
||||
if (world.isChunkLoaded(Integer.parseInt(coordinate[0])/16, Integer.parseInt(coordinate[2])/16)){
|
||||
Location sLoc = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
|
||||
CustomBlock seedBlock = CustomBlock.byAlreadyPlaced(sLoc.getBlock());
|
||||
if(seedBlock == null){
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
}else{
|
||||
String namespacedID = seedBlock.getNamespacedID();
|
||||
/*
|
||||
对之前旧版本的一些兼容
|
||||
以及一些意料之外的情况,防止报错
|
||||
*/
|
||||
if(namespacedID.equalsIgnoreCase(ConfigManager.Config.dead)){
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
return;
|
||||
}
|
||||
if(namespacedID.contains("_stage_")){
|
||||
Location potLoc = sLoc.clone().subtract(0,1,0);
|
||||
Block potBlock = potLoc.getBlock();
|
||||
CustomBlock pot = CustomBlock.byAlreadyPlaced(potBlock);
|
||||
if (pot != null){
|
||||
String potName = pot.getNamespacedID();
|
||||
/*
|
||||
是湿润的种植盆吗
|
||||
*/
|
||||
if (potName.equalsIgnoreCase(ConfigManager.Config.watered_pot)){
|
||||
String[] split = StringUtils.split(namespacedID,":");
|
||||
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||
Crop crop = ConfigManager.CONFIG.get(cropNameList[0]);
|
||||
//季节判断
|
||||
Label_out:
|
||||
if(ConfigManager.Config.season){
|
||||
if(ConfigManager.Config.greenhouse){
|
||||
for(int i = 1; i <= ConfigManager.Config.range; i++){
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(sLoc.clone().add(0,i,0).getBlock());
|
||||
if (cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.glass)){
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean ws = true;
|
||||
for(String season : crop.getSeasons()){
|
||||
if (Objects.equals(season, ConfigManager.Config.current)) {
|
||||
ws = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ws){
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> {
|
||||
CustomBlock.remove(sLoc);
|
||||
CustomBlock.place(ConfigManager.Config.dead, sLoc);
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
//下一阶段判断
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
if (CustomBlock.getInstance(split[0] +":"+cropNameList[0] + "_stage_" + nextStage) != null) {
|
||||
bukkitScheduler.callSyncMethod(CustomCrops.instance, () ->{
|
||||
CustomBlock.remove(potLoc);
|
||||
CustomBlock.place(ConfigManager.Config.pot, potLoc);
|
||||
if(Math.random()< crop.getChance()){
|
||||
CustomBlock.remove(sLoc);
|
||||
CustomBlock.place(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage, sLoc);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
//巨大化判断
|
||||
else if(crop.getWillGiant()){
|
||||
bukkitScheduler.callSyncMethod(CustomCrops.instance, () ->{
|
||||
CustomBlock.remove(potLoc);
|
||||
CustomBlock.place(ConfigManager.Config.pot, potLoc);
|
||||
if(crop.getGiantChance() > Math.random()){
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
CustomBlock.remove(sLoc);
|
||||
CustomBlock.place(crop.getGiant(), sLoc);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
是干燥的种植盆吗
|
||||
*/
|
||||
else if(potName.equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
if(ConfigManager.Config.season) {
|
||||
if(ConfigManager.Config.greenhouse){
|
||||
for(int i = 1; i <= ConfigManager.Config.range; i++){
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(sLoc.clone().add(0,i,0).getBlock());
|
||||
if (cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.glass)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean ws = true;
|
||||
Crop crop = ConfigManager.CONFIG.get(StringUtils.split(StringUtils.split(namespacedID,":")[1],"_")[0]);
|
||||
for (String season : crop.getSeasons()) {
|
||||
if (Objects.equals(season, ConfigManager.Config.current)) {
|
||||
ws = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ws) {
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> {
|
||||
CustomBlock.remove(sLoc);
|
||||
CustomBlock.place(ConfigManager.Config.dead, sLoc);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
CROPS.remove(sLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
long finish2 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7农作物生长耗时&a" + (finish2 - start2) + "&fms",Bukkit.getConsoleSender());
|
||||
}
|
||||
|
||||
/*
|
||||
阶段3:保存文件
|
||||
*/
|
||||
long start3 = System.currentTimeMillis();
|
||||
//保存数据
|
||||
public void saveData() {
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "crop.yml");
|
||||
try{
|
||||
data.save(file);
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("crop-data.yml保存出错!");
|
||||
}
|
||||
long finish3 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7农作物数据保存耗时&a" + (finish3 - start3) + "&fms",Bukkit.getConsoleSender());
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] crop.yml保存出错!</red>");
|
||||
}
|
||||
}
|
||||
|
||||
//将缓存内新数据更新到data内
|
||||
public void updateData(){
|
||||
Cache.forEach((location, String) -> {
|
||||
int x = location.getBlockX();
|
||||
int z = location.getBlockZ();
|
||||
data.set(location.getWorld().getName() + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z, String);
|
||||
});
|
||||
Cache.clear();
|
||||
}
|
||||
|
||||
//农作物生长
|
||||
public void cropGrow(String worldName){
|
||||
Long time1 = System.currentTimeMillis();
|
||||
updateData();
|
||||
Long time2 = System.currentTimeMillis();
|
||||
if(ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 农作物数据更新" + (time2-time1) + "ms");
|
||||
}
|
||||
if (data.contains(worldName)){
|
||||
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
|
||||
String[] split = StringUtils.split(chunk,",");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (ConfigReader.Config.onlyLoadedGrow || world.isChunkLoaded(Integer.parseInt(split[0]), Integer.parseInt(split[1]))){
|
||||
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
|
||||
String[] coordinate = StringUtils.split(key, ",");
|
||||
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
|
||||
CustomBlock seedBlock = CustomBlock.byAlreadyPlaced(seedLocation.getBlock());
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
//需要修改
|
||||
stringBuilder.append(worldName).append(".").append(chunk).append(".").append(key);
|
||||
if(seedBlock == null) {
|
||||
data.set(stringBuilder.toString(), null);
|
||||
return;
|
||||
}
|
||||
String namespacedID = seedBlock.getNamespacedID();
|
||||
String id = seedBlock.getId();
|
||||
if(namespacedID.equals(ConfigReader.Basic.dead)) {
|
||||
data.set(stringBuilder.toString(), null);
|
||||
return;
|
||||
}
|
||||
if(!namespacedID.contains("_stage_")) {
|
||||
data.set(stringBuilder.toString(), null);
|
||||
return;
|
||||
}
|
||||
Location potLocation = seedLocation.clone().subtract(0,1,0);
|
||||
CustomBlock pot = CustomBlock.byAlreadyPlaced(potLocation.getBlock());
|
||||
if (pot == null) return;
|
||||
String potNamespacedID = pot.getNamespacedID();
|
||||
String[] cropNameList = StringUtils.split(id,"_");
|
||||
CropInstance cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
|
||||
if (potNamespacedID.equals(ConfigReader.Basic.watered_pot)){
|
||||
//如果启用季节限制且农作物有季节需求
|
||||
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
|
||||
if (isWrongSeason(seedLocation, cropInstance.getSeasons(), worldName)){
|
||||
data.set(stringBuilder.toString(), null);
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () -> {
|
||||
CustomBlock.remove(seedLocation);
|
||||
CustomBlock.place(ConfigReader.Basic.dead, seedLocation);
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null) {
|
||||
Fertilizer fertilizer = PotManager.Cache.get(potLocation);
|
||||
if (fertilizer != null){
|
||||
int times = fertilizer.getTimes();
|
||||
if (times > 0){
|
||||
fertilizer.setTimes(times - 1);
|
||||
if (fertilizer instanceof SpeedGrow speedGrow){
|
||||
if (Math.random() < speedGrow.getChance() && CustomBlock.getInstance(StringUtils.chop(namespacedID) + (nextStage + 1)) != null){
|
||||
addStage(potLocation, seedLocation, namespacedID, nextStage + 1);
|
||||
}else {
|
||||
addStage(potLocation, seedLocation, namespacedID, nextStage);
|
||||
}
|
||||
}else if(fertilizer instanceof RetainingSoil retainingSoil){
|
||||
if (Math.random() < retainingSoil.getChance()){
|
||||
addStage(seedLocation, namespacedID, nextStage);
|
||||
}else {
|
||||
addStage(potLocation, seedLocation, namespacedID, nextStage);
|
||||
}
|
||||
}else if(fertilizer instanceof QualityCrop){
|
||||
addStage(potLocation, seedLocation, namespacedID, nextStage);
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 发现未知类型肥料,已自动清除错误数据!</red>");
|
||||
PotManager.Cache.remove(potLocation);
|
||||
}
|
||||
}else {
|
||||
PotManager.Cache.remove(potLocation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addStage(potLocation, seedLocation, namespacedID, nextStage);
|
||||
}
|
||||
}
|
||||
else if(cropInstance.getGiant() != null){
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () ->{
|
||||
CustomBlock.remove(potLocation);
|
||||
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
|
||||
if(cropInstance.getGiantChance() > Math.random()){
|
||||
data.set(stringBuilder.toString(), null);
|
||||
CustomBlock.remove(seedLocation);
|
||||
CustomBlock.place(cropInstance.getGiant(), seedLocation);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}else {
|
||||
if (cropInstance.getReturnStage() == null && !ConfigReader.Season.enable) data.set(stringBuilder.toString(), null);
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () -> {
|
||||
CustomBlock.remove(potLocation);
|
||||
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}else if(potNamespacedID.equals(ConfigReader.Basic.pot)){
|
||||
if(!ConfigReader.Season.enable || cropInstance.getSeasons() == null) return;
|
||||
if(isWrongSeason(seedLocation, cropInstance.getSeasons(), worldName)){
|
||||
data.set(stringBuilder.toString(), null);
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () -> {
|
||||
CustomBlock.remove(seedLocation);
|
||||
CustomBlock.place(ConfigReader.Basic.dead, seedLocation);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Long time3 = System.currentTimeMillis();
|
||||
if(ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 农作物生长过程" + (time3-time2) + "ms");
|
||||
}
|
||||
saveData();
|
||||
Long time4 = System.currentTimeMillis();
|
||||
if(ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 农作物数据保存" + (time4-time3) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWrongSeason(Location seedLocation, List<String> seasons, String worldName){
|
||||
if(ConfigReader.Season.greenhouse){
|
||||
for(int i = 1; i <= ConfigReader.Season.range; i++){
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(seedLocation.clone().add(0,i,0).getBlock());
|
||||
if (customBlock != null){
|
||||
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.glass)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(String season : seasons){
|
||||
if (season.equals(SeasonManager.SEASON.get(worldName))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addStage(Location potLocation, Location seedLocation, String namespacedID, int nextStage){
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () ->{
|
||||
CustomBlock.remove(potLocation);
|
||||
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
|
||||
CustomBlock.remove(seedLocation);
|
||||
CustomBlock.place(StringUtils.chop(namespacedID) + nextStage, seedLocation);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void addStage(Location seedLocation, String namespacedID, int nextStage){
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () ->{
|
||||
CustomBlock.remove(seedLocation);
|
||||
CustomBlock.place(StringUtils.chop(namespacedID) + nextStage, seedLocation);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import net.momirealms.customcrops.libs.minedown.MineDown;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MessageManager {
|
||||
public static void consoleMessage(String s, CommandSender sender) { sender.spigot().sendMessage(MineDown.parse(s)); }
|
||||
public static void playerMessage(String s, Player player){
|
||||
player.spigot().sendMessage(MineDown.parse(s));
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class NextSeason {
|
||||
|
||||
public static void changeSeason(){
|
||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||
String currentSeason = ConfigManager.Config.current;
|
||||
String nextSeason = switch (Objects.requireNonNull(currentSeason)) {
|
||||
case "spring" -> "summer";
|
||||
case "summer" -> "autumn";
|
||||
case "autumn" -> "winter";
|
||||
case "winter" -> "spring";
|
||||
default -> null;
|
||||
};
|
||||
if(nextSeason != null){
|
||||
config.set("current-season", nextSeason);
|
||||
ConfigManager.Config.current = nextSeason;
|
||||
CustomCrops.instance.saveConfig();
|
||||
}else {
|
||||
CustomCrops.instance.getLogger().warning("季节出错!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.fertilizer.QualityCrop;
|
||||
import net.momirealms.customcrops.fertilizer.RetainingSoil;
|
||||
import net.momirealms.customcrops.fertilizer.SpeedGrow;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.MemorySection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PotManager {
|
||||
|
||||
private CustomCrops plugin;
|
||||
public static ConcurrentHashMap<Location, Fertilizer> Cache = new ConcurrentHashMap<>();
|
||||
|
||||
public PotManager(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void loadData(){
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "pot.yml");
|
||||
if(!file.exists()){
|
||||
try {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 种植盆数据文件生成失败!</red>");
|
||||
}
|
||||
}
|
||||
YamlConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
data.getKeys(false).forEach(worldName -> {
|
||||
if (ConfigReader.Config.worldNames.contains(worldName)){
|
||||
data.getConfigurationSection(worldName).getValues(false).forEach((key, value) ->{
|
||||
String[] split = StringUtils.split(key, ",");
|
||||
if (value instanceof MemorySection map){
|
||||
String name = (String) map.get("fertilizer");
|
||||
Fertilizer fertilizer = ConfigReader.FERTILIZERS.get(name);
|
||||
if (fertilizer == null) return;
|
||||
if (fertilizer instanceof SpeedGrow speedGrow){
|
||||
Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new SpeedGrow(name, (int) map.get("times"), speedGrow.getChance(), speedGrow.isBefore()));
|
||||
}else if (fertilizer instanceof QualityCrop qualityCrop){
|
||||
Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new QualityCrop(name, (int) map.get("times"), qualityCrop.getChance(), qualityCrop.isBefore()));
|
||||
}else if (fertilizer instanceof RetainingSoil retainingSoil){
|
||||
Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new RetainingSoil(name, (int) map.get("times"), retainingSoil.getChance(), retainingSoil.isBefore()));
|
||||
}else {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 未知肥料类型错误!</red>");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void saveData(){
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "pot.yml");
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
Cache.forEach(((location, fertilizer) -> {
|
||||
String world = location.getWorld().getName();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
data.set(world + "." + x + "," + y + "," + z + ".fertilizer", fertilizer.getKey());
|
||||
data.set(world + "." + x + "," + y + "," + z + ".times", fertilizer.getTimes());
|
||||
}));
|
||||
try {
|
||||
data.save(file);
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public record SeasonManager(CustomCrops plugin) {
|
||||
|
||||
public static HashMap<String, String> SEASON = new HashMap<>();
|
||||
|
||||
private YamlConfiguration readData(File file) {
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 季节数据文件生成失败!</red>");
|
||||
}
|
||||
}
|
||||
return YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
public void loadData() {
|
||||
SEASON.clear();
|
||||
YamlConfiguration data = readData(new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "season.yml"));
|
||||
if (ConfigReader.Season.seasonChange) {
|
||||
autoSeason();
|
||||
} else {
|
||||
Set<String> set = data.getKeys(false);
|
||||
ConfigReader.Config.worldNames.forEach(worldName -> {
|
||||
if (set.contains(worldName)) {
|
||||
SEASON.put(worldName, data.getString(worldName));
|
||||
} else {
|
||||
getSeason(Bukkit.getWorld(worldName));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void autoSeason() {
|
||||
ConfigReader.Config.worlds.forEach(this::getSeason);
|
||||
}
|
||||
|
||||
public void getSeason(World world) {
|
||||
|
||||
int season = (int) ((world.getFullTime() / 24000L) % (ConfigReader.Season.duration * 4)) / ConfigReader.Season.duration;
|
||||
switch (season) {
|
||||
case 0 -> SEASON.put(world.getName(), "spring");
|
||||
case 1 -> SEASON.put(world.getName(), "summer");
|
||||
case 2 -> SEASON.put(world.getName(), "autumn");
|
||||
case 3 -> SEASON.put(world.getName(), "winter");
|
||||
default -> AdventureManager.consoleMessage("<red>[CustomCrops] 自动季节计算错误!</red>");
|
||||
}
|
||||
}
|
||||
|
||||
public void saveData() {
|
||||
SEASON.forEach((key, value) -> {
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "season.yml");
|
||||
YamlConfiguration data = readData(file);
|
||||
data.set(key, value);
|
||||
try {
|
||||
data.save(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] season.yml保存出错!</red>");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean setSeason(String worldName, String season){
|
||||
if (!ConfigReader.Config.worldNames.contains(worldName)){
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.asList("spring","summer","autumn","winter").contains(season)){
|
||||
return false;
|
||||
}
|
||||
SEASON.put(worldName, season);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,153 +1,124 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.utils.IAFurniture;
|
||||
import net.momirealms.customcrops.utils.Sprinkler;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.MemorySection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SprinklerManager {
|
||||
|
||||
static ConcurrentHashMap<Location, String> SPRINKLERS;
|
||||
/*
|
||||
开服的时候将文件的数据读入
|
||||
*/
|
||||
public static void loadData(){
|
||||
public YamlConfiguration data;
|
||||
private final CustomCrops plugin;
|
||||
public static ConcurrentHashMap<Location, Sprinkler> Cache = new ConcurrentHashMap<>();
|
||||
|
||||
SPRINKLERS = new ConcurrentHashMap<>();
|
||||
public SprinklerManager(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
for (String world : ConfigManager.Config.worlds) {
|
||||
if(data.getConfigurationSection(world) != null){
|
||||
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
||||
Location tempLocation = new Location(Bukkit.getWorld(world), Integer.parseInt(coordinate.split(",")[0]), Integer.parseInt(coordinate.split(",")[1]), Integer.parseInt(coordinate.split(",")[2]));
|
||||
String type = data.getString(world + "." + coordinate);
|
||||
SPRINKLERS.put(tempLocation, type);
|
||||
}
|
||||
public void loadData() {
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "sprinkler.yml");
|
||||
if(!file.exists()){
|
||||
try {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 洒水器数据文件生成失败!</red>");
|
||||
}
|
||||
}
|
||||
this.data = YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
/*
|
||||
保存数据
|
||||
*/
|
||||
public static void saveData(){
|
||||
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
Set<Map.Entry<Location, String>> en = SPRINKLERS.entrySet();
|
||||
for(Map.Entry<Location, String> entry : en){
|
||||
data.set(entry.getKey().getWorld().getName() + "." + entry.getKey().getBlockX() + "," + entry.getKey().getBlockY()+ ","+entry.getKey().getBlockZ(), entry.getValue());
|
||||
}
|
||||
try {
|
||||
public void saveData(){
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "sprinkler.yml");
|
||||
try{
|
||||
data.save(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("洒水器数据保存出错");
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] sprinkler.yml保存出错!</red>");
|
||||
}
|
||||
}
|
||||
public static void putInstance(Location location, String type) {
|
||||
SPRINKLERS.put(location, type);
|
||||
|
||||
public void updateData(){
|
||||
Cache.forEach((location, sprinklerData) -> {
|
||||
String world = location.getWorld().getName();
|
||||
int x = location.getBlockX();
|
||||
int z = location.getBlockZ();
|
||||
StringBuilder stringBuilder = new StringBuilder().append(world).append(".").append(x/16).append(",").append(z/16).append(".").append(x).append(",").append(location.getBlockY()).append(",").append(z);
|
||||
data.set(stringBuilder+".range", sprinklerData.getRange());
|
||||
data.set(stringBuilder+".water", sprinklerData.getWater());
|
||||
});
|
||||
Cache.clear();
|
||||
}
|
||||
|
||||
public static void SprinklerWork(String worldName) {
|
||||
/*
|
||||
阶段1:更新数据
|
||||
*/
|
||||
long start1 = System.currentTimeMillis();
|
||||
File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||
FileConfiguration data;
|
||||
data = YamlConfiguration.loadConfiguration(file);
|
||||
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
Set<Map.Entry<Location, String>> en = SPRINKLERS.entrySet();
|
||||
for(Map.Entry<Location, String> entry : en){
|
||||
data.set(entry.getKey().getWorld().getName() + "." + entry.getKey().getBlockX() + "," + entry.getKey().getBlockY()+ ","+entry.getKey().getBlockZ(), entry.getValue());
|
||||
public void sprinklerWork(String worldName){
|
||||
Long time1 = System.currentTimeMillis();
|
||||
updateData();
|
||||
Long time2 = System.currentTimeMillis();
|
||||
if (ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 洒水器数据更新" + (time2-time1) + "ms");
|
||||
}
|
||||
long finish1 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7洒水器数据更新耗时&a" + (finish1-start1) + "&fms",Bukkit.getConsoleSender());
|
||||
}
|
||||
/*
|
||||
阶段2:清理数据内无效的洒水器并工作
|
||||
*/
|
||||
bukkitScheduler.callSyncMethod(CustomCrops.instance,()->{
|
||||
long start2 = System.currentTimeMillis();
|
||||
//检测碰撞体积需要同步
|
||||
if(data.contains(worldName)){
|
||||
if (data.contains(worldName)){
|
||||
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
|
||||
String[] split = StringUtils.split(chunk,",");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{
|
||||
String[] coordinate = StringUtils.split(key,",");
|
||||
if (world.isChunkLoaded(Integer.parseInt(coordinate[0])/16, Integer.parseInt(coordinate[2])/16)){
|
||||
Location tempLoc = new Location(world,Double.parseDouble(coordinate[0])+0.5,Double.parseDouble(coordinate[1])+0.5,Double.parseDouble(coordinate[2])+0.5);
|
||||
if(!IAFurniture.getFromLocation(tempLoc, world)){
|
||||
SPRINKLERS.remove(tempLoc);
|
||||
data.set(worldName+"."+coordinate[0]+","+coordinate[1]+","+coordinate[2], null);
|
||||
}else {
|
||||
String type = data.getString(worldName + "." + coordinate[0] + "," + coordinate[1] + "," + coordinate[2]);
|
||||
if(type == null){
|
||||
MessageManager.consoleMessage("错误数据位于"+ worldName + coordinate[0] + "," + coordinate[1] + "," + coordinate[2], Bukkit.getConsoleSender());
|
||||
return;
|
||||
}
|
||||
if(type.equalsIgnoreCase("s1")){
|
||||
for(int i = -1; i <= 1;i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
waterPot(tempLoc.clone().add(i,-1,j));
|
||||
if (ConfigReader.Config.onlyLoadedGrow || world.isChunkLoaded(Integer.parseInt(split[0]), Integer.parseInt(split[1]))) {
|
||||
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
|
||||
String[] coordinate = StringUtils.split(key, ",");
|
||||
Location location = new Location(world,Double.parseDouble(coordinate[0])+0.5,Double.parseDouble(coordinate[1])+0.5,Double.parseDouble(coordinate[2])+0.5);
|
||||
if (value instanceof MemorySection map){
|
||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, ()->{
|
||||
int water = (int) map.get("water");
|
||||
int range = (int) map.get("range");
|
||||
if(!IAFurniture.getFromLocation(location, world)){
|
||||
data.set(worldName + "." + chunk + "." + key, null);
|
||||
return null;
|
||||
}
|
||||
if (range == 0) data.set(worldName + "." + chunk + "." + key, null);
|
||||
if (water > 0){
|
||||
data.set(worldName + "." + chunk + "." + key + ".water", water - 1);
|
||||
for(int i = -range; i <= range; i++){
|
||||
for (int j = -range; j <= range; j++){
|
||||
waterPot(location.clone().add(i,-1,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for(int i = -2; i <= 2;i++){
|
||||
for (int j = -2; j <= 2; j++){
|
||||
waterPot(tempLoc.clone().add(i,-1,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
long finish2 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7洒水器工作耗时&a" + (finish2-start2) + "&fms",Bukkit.getConsoleSender());
|
||||
}
|
||||
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance,()->{
|
||||
/*
|
||||
阶段3:保存数据
|
||||
*/
|
||||
long start3 = System.currentTimeMillis();
|
||||
try{
|
||||
data.save(file);
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("sprinkler-data.yml保存出错!");
|
||||
}
|
||||
long finish3 = System.currentTimeMillis();
|
||||
if (ConfigManager.Config.log_time){
|
||||
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops] &7洒水器数据保存耗时&a" + (finish3-start3) + "&fms",Bukkit.getConsoleSender());
|
||||
});
|
||||
}
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
Long time3 = System.currentTimeMillis();
|
||||
if(ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 洒水器工作过程" + (time3-time2) + "ms");
|
||||
}
|
||||
saveData();
|
||||
Long time4 = System.currentTimeMillis();
|
||||
if(ConfigReader.Config.logTime){
|
||||
AdventureManager.consoleMessage("性能监测: 洒水器数据保存" + (time4-time3) + "ms");
|
||||
}
|
||||
}
|
||||
private static void waterPot(Location tempLoc) {
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
|
||||
private void waterPot(Location potLoc) {
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(potLoc.getBlock());
|
||||
if(cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place((ConfigManager.Config.watered_pot), tempLoc);
|
||||
if(cb.getNamespacedID().equals(ConfigReader.Basic.pot)){
|
||||
CustomBlock.remove(potLoc);
|
||||
CustomBlock.place(ConfigReader.Basic.watered_pot, potLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.momirealms.customcrops.fertilizer;
|
||||
|
||||
public interface Fertilizer {
|
||||
String getKey();
|
||||
int getTimes();
|
||||
void setTimes(int times);
|
||||
boolean isBefore();
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.momirealms.customcrops.fertilizer;
|
||||
|
||||
public class QualityCrop implements Fertilizer{
|
||||
|
||||
private int[] chance;
|
||||
private String key;
|
||||
private int times;
|
||||
private boolean before;
|
||||
private String name;
|
||||
|
||||
public QualityCrop(String key, int times, int[] chance, boolean before) {
|
||||
this.chance = chance;
|
||||
this.times = times;
|
||||
this.before = before;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimes() {
|
||||
return this.times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(int times) {
|
||||
this.times = times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBefore() {
|
||||
return this.before;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setChance(int[] chance) {
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public int[] getChance() {
|
||||
return chance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.momirealms.customcrops.fertilizer;
|
||||
|
||||
public class RetainingSoil implements Fertilizer{
|
||||
|
||||
private double chance;
|
||||
private String key;
|
||||
private int times;
|
||||
private boolean before;
|
||||
public String name;
|
||||
|
||||
public RetainingSoil(String key, int times, double chance, boolean before){
|
||||
this.times = times;
|
||||
this.chance = chance;
|
||||
this.before = before;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimes() {
|
||||
return this.times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(int times) {
|
||||
this.times = times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBefore() {
|
||||
return this.before;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setChance(double chance) {
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public double getChance() {
|
||||
return chance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.momirealms.customcrops.fertilizer;
|
||||
|
||||
public class SpeedGrow implements Fertilizer{
|
||||
|
||||
private double chance;
|
||||
private String key;
|
||||
private int times;
|
||||
private boolean before;
|
||||
private String name;
|
||||
|
||||
public SpeedGrow(String key, int times, double chance, boolean before){
|
||||
this.chance = chance;
|
||||
this.times = times;
|
||||
this.before = before;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimes() {
|
||||
return this.times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(int times) {
|
||||
this.times = times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBefore() {
|
||||
return this.before;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public double getChance() {
|
||||
return chance;
|
||||
}
|
||||
|
||||
public void setChance(double chance) {
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public record GriefDefender() implements Integration {
|
||||
|
||||
@Override
|
||||
public boolean canBreak(Location location, Player player) {
|
||||
return com.griefdefender.api.GriefDefender.getCore().getUser(player.getUniqueId()).canBreak(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlace(Location location, Player player) {
|
||||
return com.griefdefender.api.GriefDefender.getCore().getUser(player.getUniqueId()).canPlace(player.getInventory().getItemInMainHand(), location);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import com.griefdefender.api.GriefDefender;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class GriefDefenderIntegrations {
|
||||
|
||||
public static boolean checkGDBreak(Location location, Player player){
|
||||
return GriefDefender.getCore().getUser(player.getUniqueId()).canBreak(location);
|
||||
}
|
||||
|
||||
public static boolean checkGDBuild(Location location, Player player){
|
||||
return GriefDefender.getCore().getUser(player.getUniqueId()).canPlace(player.getInventory().getItemInMainHand(), location);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface Integration {
|
||||
boolean canBreak(Location location, Player player);
|
||||
boolean canPlace(Location location, Player player);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class IntegrationCheck {
|
||||
|
||||
//收获权限检测
|
||||
public static boolean HarvestCheck(Location location, Player player){
|
||||
if(ConfigManager.Config.res){
|
||||
if(!ResidenceIntegrations.checkResHarvest(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.king){
|
||||
if(!KingdomsXIntegrations.checkKDBuild(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.wg){
|
||||
if(!WorldGuardIntegrations.checkWGHarvest(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.gd){
|
||||
if(!GriefDefenderIntegrations.checkGDBreak(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//种植等权限检测
|
||||
public static boolean PlaceCheck(Location location, Player player){
|
||||
if(ConfigManager.Config.res){
|
||||
if(!ResidenceIntegrations.checkResBuild(location,player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.king){
|
||||
if(!KingdomsXIntegrations.checkKDBuild(location,player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.wg){
|
||||
if(!WorldGuardIntegrations.checkWGBuild(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ConfigManager.Config.gd){
|
||||
if(!GriefDefenderIntegrations.checkGDBuild(location, player)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,19 @@ import org.kingdoms.constants.group.Kingdom;
|
||||
import org.kingdoms.constants.land.Land;
|
||||
import org.kingdoms.constants.player.KingdomPlayer;
|
||||
|
||||
public class KingdomsXIntegrations {
|
||||
public static boolean checkKDBuild(Location location, Player player){
|
||||
public record KingdomsX() implements Integration {
|
||||
|
||||
@Override
|
||||
public boolean canBreak(Location location, Player player) {
|
||||
return kingdomsCheck(location, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlace(Location location, Player player) {
|
||||
return kingdomsCheck(location, player);
|
||||
}
|
||||
|
||||
private boolean kingdomsCheck(Location location, Player player) {
|
||||
Land land = Land.getLand(location);
|
||||
if (land == null) return true;
|
||||
if (land.isClaimed()) {
|
||||
@@ -16,7 +27,7 @@ public class KingdomsXIntegrations {
|
||||
if (kp.getKingdom() != null) {
|
||||
Kingdom kingdom = kp.getKingdom();
|
||||
return kingdom != cropKingdom;
|
||||
}else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ import com.bekvon.bukkit.residence.protection.ResidencePermissions;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ResidenceIntegrations {
|
||||
public static boolean checkResBuild(Location location, Player player){
|
||||
public record Residence() implements Integration {
|
||||
|
||||
@Override
|
||||
public boolean canBreak(Location location, Player player) {
|
||||
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
||||
if(res!=null){
|
||||
ResidencePermissions perms = res.getPermissions();
|
||||
@@ -15,7 +17,9 @@ public class ResidenceIntegrations {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static boolean checkResHarvest(Location location, Player player){
|
||||
|
||||
@Override
|
||||
public boolean canPlace(Location location, Player player) {
|
||||
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
||||
if(res!=null){
|
||||
ResidencePermissions perms = res.getPermissions();
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import com.sk89q.worldguard.protection.regions.RegionQuery;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public record WorldGuard() implements Integration {
|
||||
|
||||
@Override
|
||||
public boolean canPlace(Location location, Player player) {
|
||||
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
RegionContainer container = com.sk89q.worldguard.WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
RegionQuery query = container.createQuery();
|
||||
ApplicableRegionSet set = query.getApplicableRegions(BukkitAdapter.adapt(location));
|
||||
if (set != null){
|
||||
System.out.println(set);
|
||||
return query.testState(BukkitAdapter.adapt(location), localPlayer, Flags.BUILD);
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBreak(Location location, Player player) {
|
||||
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
RegionContainer container = com.sk89q.worldguard.WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
RegionQuery query = container.createQuery();
|
||||
ApplicableRegionSet set = query.getApplicableRegions(BukkitAdapter.adapt(location));
|
||||
if (set != null){
|
||||
System.out.println(set);
|
||||
return query.testState(BukkitAdapter.adapt(location), localPlayer, Flags.BLOCK_BREAK);
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.momirealms.customcrops.integrations;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import com.sk89q.worldguard.protection.regions.RegionQuery;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class WorldGuardIntegrations {
|
||||
public static boolean checkWGBuild(Location loc,Player player){
|
||||
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
RegionQuery query = container.createQuery();
|
||||
return query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BUILD);
|
||||
}
|
||||
public static boolean checkWGHarvest(Location loc,Player player){
|
||||
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
RegionQuery query = container.createQuery();
|
||||
return query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BLOCK_BREAK);
|
||||
}
|
||||
}
|
||||
@@ -1,499 +0,0 @@
|
||||
package net.momirealms.customcrops.libs.minedown;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <h2>MineDown</h2>
|
||||
* A MarkDown inspired markup for Minecraft chat components
|
||||
* <p>
|
||||
* This lets you convert string messages into chat components by using a custom mark up syntax
|
||||
* which is loosely based on MarkDown while still supporting legacy formatting codes.
|
||||
*
|
||||
* <table>
|
||||
* <caption><strong> Inline Formatting </strong></caption>
|
||||
* <tr><td> Color legacy </td><td><code> &6Text </code></td><td> {@link ChatColor} codes </td></tr>
|
||||
* <tr><td> Color </td><td><code> &gold&Text </code></td><td> {@link ChatColor} codes </td></tr>
|
||||
* <tr><td> RGB Hex Color </td><td><code> &ff00ff&Text </code></td><td> Full hexadecimal format </td></tr>
|
||||
* <tr><td> RGB Hex Color </td><td><code> &f0f&Text </code></td><td> Short format (equivalent to long one) </td></tr>
|
||||
* <tr><td> Bold </td><td><code> **Text** </code></td></tr>
|
||||
* <tr><td> Italic </td><td><code> ##Text## </code></td></tr>
|
||||
* <tr><td> Underlined </td><td><code> __Text__ </code></td></tr>
|
||||
* <tr><td> Strikethrough </td><td><code> ~~Text~~ </code></td></tr>
|
||||
* <tr><td> Obfuscated </td><td><code> ??Text?? </code></td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <h3>Events</h3>
|
||||
* You can define click and hover events with the commonly used MarkDown link syntax.
|
||||
* <p>
|
||||
* <table>
|
||||
* <caption><strong> Simple Syntax </strong></caption>
|
||||
* <tr><td> General syntax </td><td><code> [Text](text-color text-formatting... link hover text) </code></td></tr>
|
||||
* <tr><td> Simple Link </td><td><code> [Text](https://example.com) </code></td></tr>
|
||||
* <tr><td> Simple Command </td><td><code> [Text](/command to run) </code></td></tr>
|
||||
* <tr><td> Link + Hover </td><td><code> [Text](https://example.com Hover Text) </code></td></tr>
|
||||
* <tr><td> Text formatting + Link + Hover </td><td><code> [Text](blue underline https://example.com Hover Text) </code></td></tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* <table>
|
||||
* <caption><strong> Advanced Syntax </strong></caption>
|
||||
* <tr><td> General syntax </td><td><code> [Text](action=value) </code></td><td> {@link ClickEvent.Action}, {@link HoverEvent.Action} </td></tr>
|
||||
* <tr><td> Link </td><td><code> [Text](open_url=https://example.com) </code></td></tr>
|
||||
* <tr><td> Color </td><td><code> [Text](color=red) </code></td></tr>
|
||||
* <tr><td> RGB Hex Color </td><td><code> [Text](color=#ff00ff) </code></td><td> Full hexadecimal format </td></tr>
|
||||
* <tr><td> RGB Hex Color </td><td><code> [Text](color=#f0f) </code></td><td> Short format (equivalent to long one) </td></tr>
|
||||
* <tr><td> Formatting </td><td><code> [Text](format=underline,bold) </code></td></tr>
|
||||
* <tr><td> Font </td><td><code> [Text](format=underline,bold) </code></td></tr>
|
||||
* <tr><td> Run Command </td><td><code> [Text](run_command=/command string) </code></td></tr>
|
||||
* <tr><td> Suggest Command </td><td><code> [Text](suggest_command=/command) </code></td></tr>
|
||||
* <tr><td> Simple Hover </td><td><code> [Text](hover=Hover Text) </code></td></tr>
|
||||
* <tr><td> Hover Text </td><td><code> [Text](show_text=Hover Text) </code></td></tr>
|
||||
* <tr><td> Hover Entity Info </td><td><code> [Text](show_entity=uuid:pig Name) </code></td></tr>
|
||||
* <tr><td> Hover Item Info </td><td><code> [Text](show_item=stone*2 nbt...) </code></td></tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* All advanced settings can be chained/included in a event definition.
|
||||
* You can't however add multiple different colors or click and hover actions!
|
||||
*/
|
||||
public class MineDown {
|
||||
public static final String FONT_PREFIX = "font=";
|
||||
public static final String COLOR_PREFIX = "color=";
|
||||
public static final String FORMAT_PREFIX = "format=";
|
||||
public static final String HOVER_PREFIX = "hover=";
|
||||
public static final String INSERTION_PREFIX = "insert=";
|
||||
|
||||
private String message;
|
||||
private final Replacer replacer = new Replacer();
|
||||
private final MineDownParser parser = new MineDownParser();
|
||||
private BaseComponent[] baseComponents = null;
|
||||
private boolean replaceFirst = Boolean.getBoolean("de.themoep.minedown.replacefirst");
|
||||
|
||||
/**
|
||||
* Create a new MineDown builder with a certain message
|
||||
* @param message The message to parse
|
||||
*/
|
||||
public MineDown(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a MineDown string to components
|
||||
* @param message The message to translate
|
||||
* @param replacements Optional placeholder replacements
|
||||
* @return The parsed components
|
||||
*/
|
||||
public static BaseComponent[] parse(String message, String... replacements) {
|
||||
return new MineDown(message).replace(replacements).toComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert components to a MineDown string
|
||||
* @param components The components to convert
|
||||
* @return The components represented as a MineDown string
|
||||
*/
|
||||
public static String stringify(BaseComponent[] components) {
|
||||
return new MineDownStringifier().stringify(components);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and convert the message to the component
|
||||
* @return The parsed component message
|
||||
*/
|
||||
public BaseComponent[] toComponent() {
|
||||
if (baseComponents() == null) {
|
||||
if (replaceFirst()) {
|
||||
Replacer componentReplacer = new Replacer();
|
||||
for (Map.Entry<String, BaseComponent[]> entry : replacer().componentReplacements().entrySet()) {
|
||||
componentReplacer.replace(entry.getKey(), stringify(entry.getValue()));
|
||||
}
|
||||
baseComponents = parser().parse(componentReplacer.replaceIn(replacer().replaceIn(message()))).create();
|
||||
} else {
|
||||
baseComponents = replacer().replaceIn(parser().parse(message()).create());
|
||||
}
|
||||
}
|
||||
return baseComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cached component and re-parse the next time {@link #toComponent} is called
|
||||
*/
|
||||
private void reset() {
|
||||
baseComponents = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not replacements should be replaced before or after the components are created.
|
||||
* When replacing first it will not replace any placeholders with component replacement values!
|
||||
* Default is after. (replaceFirst = false)
|
||||
* @param replaceFirst Whether or not to replace first or parse first
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown replaceFirst(boolean replaceFirst) {
|
||||
reset();
|
||||
this.replaceFirst = replaceFirst;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not replacements should be replaced before or after the components are created.
|
||||
* When replacing first it will not replace any placeholders with component replacement values!
|
||||
* Default is after. (replaceFirst = false)
|
||||
* @return Whether or not to replace first or parse first
|
||||
*/
|
||||
public boolean replaceFirst() {
|
||||
return replaceFirst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array with placeholders and values that should get replaced in the message
|
||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown replace(String... replacements) {
|
||||
reset();
|
||||
replacer().replace(replacements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a map with placeholders and values that should get replaced in the message
|
||||
* @param replacements The replacements mapped placeholder to value
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown replace(Map<String, ?> replacements) {
|
||||
reset();
|
||||
replacer().replace(replacements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a placeholder to component mapping that should get replaced in the message
|
||||
* @param placeholder The placeholder to replace
|
||||
* @param replacement The replacement components
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public MineDown replace(String placeholder, BaseComponent... replacement) {
|
||||
reset();
|
||||
replacer().replace(placeholder,replacement);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator for both prefix and suffix
|
||||
* @param placeholderIndicator The character to use as a placeholder indicator
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown placeholderIndicator(String placeholderIndicator) {
|
||||
placeholderPrefix(placeholderIndicator);
|
||||
placeholderSuffix(placeholderIndicator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator's prefix character
|
||||
* @param placeholderPrefix The character to use as the placeholder indicator's prefix
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown placeholderPrefix(String placeholderPrefix) {
|
||||
reset();
|
||||
replacer().placeholderPrefix(placeholderPrefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the placeholder indicator's prefix character
|
||||
* @return The placeholder indicator's prefix character
|
||||
*/
|
||||
public String placeholderPrefix() {
|
||||
return replacer().placeholderPrefix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator's suffix character
|
||||
* @param placeholderSuffix The character to use as the placeholder indicator's suffix
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown placeholderSuffix(String placeholderSuffix) {
|
||||
reset();
|
||||
replacer().placeholderSuffix(placeholderSuffix);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the placeholder indicator's suffix character
|
||||
* @return The placeholder indicator's suffix character
|
||||
*/
|
||||
public String placeholderSuffix() {
|
||||
return replacer().placeholderSuffix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the case of the placeholder should be ignored when replacing
|
||||
* @param ignorePlaceholderCase Whether or not to ignore the case of the placeholders
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown ignorePlaceholderCase(boolean ignorePlaceholderCase) {
|
||||
reset();
|
||||
replacer().ignorePlaceholderCase(ignorePlaceholderCase);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not the case of the placeholder should be ignored when replacing
|
||||
* @return Whether or not to ignore the case of the placeholders
|
||||
*/
|
||||
public boolean ignorePlaceholderCase() {
|
||||
return replacer().ignorePlaceholderCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the translation of legacy color codes
|
||||
* @param translateLegacyColors Whether or not to translate legacy color codes (Default: true)
|
||||
* @return The MineDown instance
|
||||
* @deprecated Use {@link #enable(MineDownParser.Option)} and {@link #disable(MineDownParser.Option)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MineDown translateLegacyColors(boolean translateLegacyColors) {
|
||||
reset();
|
||||
parser().translateLegacyColors(translateLegacyColors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect urls in strings and add events to them? (Default: true)
|
||||
* @param enabled Whether or not to detect URLs and add events to them
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown urlDetection(boolean enabled) {
|
||||
reset();
|
||||
parser().urlDetection(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically add http to values of open_url when there doesn't exist any? (Default: true)
|
||||
* @param enabled Whether or not to automatically add http when missing
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown autoAddUrlPrefix(boolean enabled) {
|
||||
reset();
|
||||
parser().autoAddUrlPrefix(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The text to display when hovering over an URL
|
||||
* @param text The text to display when hovering over an URL
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown urlHoverText(String text) {
|
||||
reset();
|
||||
parser().urlHoverText(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max width the hover text should have.
|
||||
* Minecraft itself will wrap after 60 characters.
|
||||
* Won't apply if the text already includes new lines.
|
||||
* @param hoverTextWidth The url hover text length
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown hoverTextWidth(int hoverTextWidth) {
|
||||
reset();
|
||||
parser().hoverTextWidth(hoverTextWidth);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable an option. Unfilter it if you filtered it before.
|
||||
* @param option The option to enable
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown enable(MineDownParser.Option option) {
|
||||
reset();
|
||||
parser().enable(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable an option. Disabling an option will stop the parser from replacing
|
||||
* this option's chars in the string. Use {@link #filter(MineDownParser.Option)} to completely
|
||||
* remove the characters used by this option from the message instead.
|
||||
* @param option The option to disable
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown disable(MineDownParser.Option option) {
|
||||
reset();
|
||||
parser().disable(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter an option. This completely removes the characters of this option from
|
||||
* the string ignoring whether the option is enabled or not.
|
||||
* @param option The option to add to the filter
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown filter(MineDownParser.Option option) {
|
||||
reset();
|
||||
parser().filter(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfilter an option. Does not enable it!
|
||||
* @param option The option to remove from the filter
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown unfilter(MineDownParser.Option option) {
|
||||
reset();
|
||||
parser().unfilter(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a special character to replace color codes by if translating legacy colors is enabled.
|
||||
* @param colorChar The character to use as a special color code. (Default: ampersand &)
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown colorChar(char colorChar) {
|
||||
reset();
|
||||
parser().colorChar(colorChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set message that is to be parsed
|
||||
* @return The to be parsed message
|
||||
*/
|
||||
public String message() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message that is to be parsed
|
||||
* @param message The message to be parsed
|
||||
* @return The MineDown instance
|
||||
*/
|
||||
public MineDown message(String message) {
|
||||
this.message = message;
|
||||
reset();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the replacer instance that is currently used
|
||||
* @return The currently used replacer instance
|
||||
*/
|
||||
public Replacer replacer() {
|
||||
return this.replacer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parser instance that is currently used
|
||||
* @return The currently used parser instance
|
||||
*/
|
||||
public MineDownParser parser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
protected BaseComponent[] baseComponents() {
|
||||
return this.baseComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all MineDown settings to a new instance
|
||||
* @return The new MineDown instance with all settings copied
|
||||
*/
|
||||
public MineDown copy() {
|
||||
return new MineDown(message()).copy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all MineDown settings from another one
|
||||
* @param from The MineDown to copy from
|
||||
* @return This MineDown instance
|
||||
*/
|
||||
public MineDown copy(MineDown from) {
|
||||
replacer().copy(from.replacer());
|
||||
parser().copy(from.parser());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string that represents the format in MineDown
|
||||
* @param format The format
|
||||
* @return The MineDown string or an empty one if it's not a format
|
||||
*/
|
||||
public static String getFormatString(ChatColor format) {
|
||||
if (format == ChatColor.BOLD) {
|
||||
return "**";
|
||||
} else if (format == ChatColor.ITALIC) {
|
||||
return "##";
|
||||
} else if (format == ChatColor.UNDERLINE) {
|
||||
return "__";
|
||||
} else if (format == ChatColor.STRIKETHROUGH) {
|
||||
return "~~";
|
||||
} else if (format == ChatColor.MAGIC) {
|
||||
return "??";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ChatColor format from a MineDown string
|
||||
* @param c The character
|
||||
* @return The ChatColor of that format or <code>null</code> it none was found
|
||||
*/
|
||||
public static ChatColor getFormatFromChar(char c) {
|
||||
switch (c) {
|
||||
case '~':
|
||||
return ChatColor.STRIKETHROUGH;
|
||||
case '_':
|
||||
return ChatColor.UNDERLINE;
|
||||
case '*':
|
||||
return ChatColor.BOLD;
|
||||
case '#':
|
||||
return ChatColor.ITALIC;
|
||||
case '?':
|
||||
return ChatColor.MAGIC;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape all MineDown formatting in a string. This will escape backslashes too!
|
||||
* @param string The string to escape in
|
||||
* @return The string with formatting escaped
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
return new MineDown(string).parser().escape(string);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,423 +0,0 @@
|
||||
package net.momirealms.customcrops.libs.minedown;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Content;
|
||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
import static net.momirealms.customcrops.libs.minedown.MineDown.COLOR_PREFIX;
|
||||
import static net.momirealms.customcrops.libs.minedown.MineDown.FONT_PREFIX;
|
||||
import static net.momirealms.customcrops.libs.minedown.MineDown.FORMAT_PREFIX;
|
||||
import static net.momirealms.customcrops.libs.minedown.MineDown.HOVER_PREFIX;
|
||||
import static net.momirealms.customcrops.libs.minedown.MineDown.INSERTION_PREFIX;
|
||||
|
||||
public class MineDownStringifier {
|
||||
|
||||
private static final boolean HAS_FONT_SUPPORT = Util.hasMethod(BaseComponent.class, "getFontRaw");
|
||||
private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
|
||||
private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
|
||||
private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
|
||||
|
||||
/**
|
||||
* Whether or not to use legacy color codes (Default: false)
|
||||
*/
|
||||
private boolean useLegacyColors = false;
|
||||
|
||||
/**
|
||||
* Whether or not to translate legacy formatting codes over Minedown ones (Default: false)
|
||||
*/
|
||||
private boolean useLegacyFormatting = false;
|
||||
|
||||
/**
|
||||
* Whether or not to use simple event definitions or specific ones (Default: true)
|
||||
*/
|
||||
private boolean preferSimpleEvents = true;
|
||||
|
||||
/**
|
||||
* Whether or not to put formatting in event definitions (Default: false)
|
||||
*/
|
||||
private boolean formattingInEventDefinition = false;
|
||||
|
||||
/**
|
||||
* Whether or not to put colors in event definitions (Default: true)
|
||||
*/
|
||||
private boolean colorInEventDefinition = true;
|
||||
|
||||
/**
|
||||
* The character to use as a special color code. (Default: ampersand &)
|
||||
*/
|
||||
private char colorChar = '&';
|
||||
|
||||
private StringBuilder value = new StringBuilder();
|
||||
|
||||
private ChatColor color = null;
|
||||
private ClickEvent clickEvent = null;
|
||||
private HoverEvent hoverEvent = null;
|
||||
private Set<ChatColor> formats = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* Create a {@link MineDown} string from a component message
|
||||
* @param components The components to generate a MineDown string from
|
||||
* @return The MineDown string
|
||||
*/
|
||||
public String stringify(BaseComponent... components) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (BaseComponent component : components) {
|
||||
if (!component.hasFormatting()) {
|
||||
appendText(sb, component);
|
||||
continue;
|
||||
}
|
||||
boolean hasEvent = component.getFontRaw() != null || component.getInsertion() != null
|
||||
|| component.getClickEvent() != clickEvent || component.getHoverEvent() != hoverEvent;
|
||||
if (hasEvent) {
|
||||
sb.append('[');
|
||||
if (!formattingInEventDefinition()) {
|
||||
appendFormat(sb, component);
|
||||
}
|
||||
if (!colorInEventDefinition()) {
|
||||
appendColor(sb, component.getColor());
|
||||
}
|
||||
} else if (component.getColorRaw() != null) {
|
||||
appendFormat(sb, component);
|
||||
appendColor(sb, component.getColor());
|
||||
} else {
|
||||
appendFormat(sb, component);
|
||||
}
|
||||
|
||||
appendText(sb, component);
|
||||
|
||||
if (component.getExtra() != null && !component.getExtra().isEmpty()) {
|
||||
sb.append(copy().stringify(component.getExtra().toArray(new BaseComponent[0])));
|
||||
}
|
||||
|
||||
if (hasEvent) {
|
||||
clickEvent = component.getClickEvent();
|
||||
hoverEvent = component.getHoverEvent();
|
||||
if (!formattingInEventDefinition()) {
|
||||
appendFormatSuffix(sb, component);
|
||||
}
|
||||
sb.append("](");
|
||||
List<String> definitions = new ArrayList<>();
|
||||
if (colorInEventDefinition()) {
|
||||
StringBuilder sbi = new StringBuilder();
|
||||
if (!preferSimpleEvents()) {
|
||||
sbi.append(COLOR_PREFIX);
|
||||
}
|
||||
sbi.append(component.getColor().getName().toLowerCase(Locale.ROOT));
|
||||
definitions.add(sbi.toString());
|
||||
}
|
||||
if (formattingInEventDefinition()) {
|
||||
StringBuilder sbi = new StringBuilder();
|
||||
if (!preferSimpleEvents) {
|
||||
sbi.append(FORMAT_PREFIX);
|
||||
}
|
||||
sbi.append(Util.getFormats(component, true).stream().map(c -> c.getName().toLowerCase(Locale.ROOT)).collect(Collectors.joining(" ")));
|
||||
definitions.add(sbi.toString());
|
||||
}
|
||||
if (HAS_FONT_SUPPORT && component.getFontRaw() != null) {
|
||||
definitions.add(FONT_PREFIX + component.getFontRaw());
|
||||
}
|
||||
if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
|
||||
if (component.getInsertion().contains(" ")) {
|
||||
definitions.add(INSERTION_PREFIX + "{" + component.getInsertion() + "}");
|
||||
} else {
|
||||
definitions.add(INSERTION_PREFIX + component.getInsertion());
|
||||
}
|
||||
}
|
||||
if (component.getClickEvent() != null) {
|
||||
if (preferSimpleEvents() && component.getClickEvent().getAction() == ClickEvent.Action.OPEN_URL) {
|
||||
definitions.add(component.getClickEvent().getValue());
|
||||
} else {
|
||||
definitions.add(component.getClickEvent().getAction().toString().toLowerCase(Locale.ROOT) + "=" + component.getClickEvent().getValue());
|
||||
}
|
||||
}
|
||||
if (component.getHoverEvent() != null) {
|
||||
StringBuilder sbi = new StringBuilder();
|
||||
if (preferSimpleEvents() && component.getHoverEvent().getAction() == HoverEvent.Action.SHOW_TEXT &&
|
||||
(component.getClickEvent() == null || component.getClickEvent().getAction() != ClickEvent.Action.OPEN_URL)) {
|
||||
sbi.append(HOVER_PREFIX);
|
||||
} else {
|
||||
sbi.append(component.getHoverEvent().getAction().toString().toLowerCase(Locale.ROOT)).append('=');
|
||||
}
|
||||
if (HAS_HOVER_CONTENT_SUPPORT) {
|
||||
sbi.append(copy().stringify(component.getHoverEvent().getContents()));
|
||||
} else if (HOVER_GET_VALUE != null) {
|
||||
try {
|
||||
sbi.append(copy().stringify((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent())));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
definitions.add(sbi.toString());
|
||||
}
|
||||
sb.append(definitions.stream().collect(Collectors.joining(" ")));
|
||||
sb.append(')');
|
||||
} else {
|
||||
appendFormatSuffix(sb, component);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private StringBuilder stringify(List<Content> contents) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Content content : contents) {
|
||||
if (content instanceof Text) {
|
||||
Object value = ((Text) content).getValue();
|
||||
if (value instanceof BaseComponent[]) {
|
||||
sb.append(stringify((BaseComponent[]) value));
|
||||
} else {
|
||||
sb.append(value);
|
||||
}
|
||||
} else if (content instanceof Entity) {
|
||||
Entity contentEntity = (Entity) content;
|
||||
sb.append(contentEntity.getId());
|
||||
if (contentEntity.getType() != null) {
|
||||
sb.append(":").append(contentEntity.getType());
|
||||
}
|
||||
if (contentEntity.getName() != null) {
|
||||
sb.append(" ").append(stringify(contentEntity.getName()));
|
||||
}
|
||||
} else if (content instanceof Item) {
|
||||
Item contentItem = (Item) content;
|
||||
sb.append(contentItem.getId());
|
||||
if (contentItem.getCount() > 0) {
|
||||
sb.append("*").append(contentItem.getCount());
|
||||
}
|
||||
if (contentItem.getTag() != null) {
|
||||
sb.append(" ").append(contentItem.getTag().getNbt());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
private void appendText(StringBuilder sb, BaseComponent component) {
|
||||
if (component instanceof TextComponent) {
|
||||
sb.append(((TextComponent) component).getText());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot stringify " + component.getClass().getTypeName() + " yet! Only TextComponents are supported right now. Sorry. :(");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendColor(StringBuilder sb, ChatColor color) {
|
||||
if (this.color != color) {
|
||||
this.color = color;
|
||||
if (useLegacyColors()) {
|
||||
sb.append(colorChar()).append(color.toString().substring(1));
|
||||
} else {
|
||||
sb.append(colorChar()).append(color.getName()).append(colorChar());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendFormat(StringBuilder sb, BaseComponent component) {
|
||||
Set<ChatColor> formats = Util.getFormats(component, true);
|
||||
if (!formats.containsAll(this.formats)) {
|
||||
if (useLegacyFormatting()) {
|
||||
sb.append(colorChar()).append(ChatColor.RESET.toString().charAt(1));
|
||||
} else {
|
||||
Deque<ChatColor> formatDeque = new ArrayDeque<>(this.formats);
|
||||
while (!formatDeque.isEmpty()) {
|
||||
ChatColor format = formatDeque.pollLast();
|
||||
if (!formats.contains(format)) {
|
||||
sb.append(MineDown.getFormatString(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
formats.removeAll(this.formats);
|
||||
}
|
||||
for (ChatColor format : formats) {
|
||||
if (useLegacyFormatting()) {
|
||||
sb.append(colorChar()).append(format.toString().charAt(1));
|
||||
} else {
|
||||
sb.append(MineDown.getFormatString(format));
|
||||
}
|
||||
}
|
||||
this.formats.clear();
|
||||
this.formats.addAll(formats);
|
||||
}
|
||||
|
||||
private void appendFormatSuffix(StringBuilder sb, BaseComponent component) {
|
||||
if (!useLegacyFormatting()) {
|
||||
Set<ChatColor> formats = Util.getFormats(component, true);
|
||||
for (ChatColor format : formats) {
|
||||
sb.append(MineDown.getFormatString(format));
|
||||
}
|
||||
this.formats.removeAll(formats);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the parser's setting to a new instance
|
||||
* @return The new parser instance with all settings copied
|
||||
*/
|
||||
public MineDownStringifier copy() {
|
||||
return new MineDownStringifier().copy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the parser's settings from another parser
|
||||
* @param from The stringifier to copy from
|
||||
* @return This stringifier's instance
|
||||
*/
|
||||
public MineDownStringifier copy(MineDownStringifier from) {
|
||||
MineDownStringifier copy = new MineDownStringifier();
|
||||
useLegacyColors(from.useLegacyColors());
|
||||
useLegacyFormatting(from.useLegacyFormatting());
|
||||
preferSimpleEvents(from.preferSimpleEvents());
|
||||
formattingInEventDefinition(from.formattingInEventDefinition());
|
||||
colorInEventDefinition(from.colorInEventDefinition());
|
||||
colorChar(from.colorChar());
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not to use legacy color codes
|
||||
* @return whether or not to use legacy color codes when possible (Default: true)
|
||||
*/
|
||||
public boolean useLegacyColors() {
|
||||
return this.useLegacyColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to use legacy color codes
|
||||
* @param useLegacyColors Whether or not to use legacy colors (Default: true)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier useLegacyColors(boolean useLegacyColors) {
|
||||
this.useLegacyColors = useLegacyColors;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not to translate legacy formatting codes over MineDown ones
|
||||
* @return whether or not to use legacy formatting codes (Default: false)
|
||||
*/
|
||||
public boolean useLegacyFormatting() {
|
||||
return this.useLegacyFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to translate legacy formatting codes over MineDown ones
|
||||
* @param useLegacyFormatting Whether or not to translate legacy formatting codes (Default: false)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier useLegacyFormatting(boolean useLegacyFormatting) {
|
||||
this.useLegacyFormatting = useLegacyFormatting;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not to use simple event definitions or specific ones (Default: true)
|
||||
* @return whether or not to use simple events
|
||||
*/
|
||||
public boolean preferSimpleEvents() {
|
||||
return this.preferSimpleEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to use simple event definitions or specific ones
|
||||
* @param preferSimpleEvents Whether or not to prefer simple events (Default: true)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier preferSimpleEvents(boolean preferSimpleEvents) {
|
||||
this.preferSimpleEvents = preferSimpleEvents;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not to put colors in event definitions or use inline color definitions
|
||||
* @return whether or not to put colors in event definitions (Default: false)
|
||||
*/
|
||||
public boolean colorInEventDefinition() {
|
||||
return this.colorInEventDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to put colors in event definitions or use inline color definitions
|
||||
* @param colorInEventDefinition Whether or not to put colors in event definitions (Default: false)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier colorInEventDefinition(boolean colorInEventDefinition) {
|
||||
this.colorInEventDefinition = colorInEventDefinition;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not to put formatting in event definitions or use inline formatting definitions
|
||||
* @return whether or not to put formatting in event definitions (Default: false)
|
||||
*/
|
||||
public boolean formattingInEventDefinition() {
|
||||
return this.formattingInEventDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to put formatting in event definitions or use inline formatting definitions
|
||||
* @param formattingInEventDefinition Whether or not to put formatting in event definitions (Default: false)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier formattingInEventDefinition(boolean formattingInEventDefinition) {
|
||||
this.formattingInEventDefinition = formattingInEventDefinition;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character to use as a special color code. (Default: ampersand &)
|
||||
* @return the color character
|
||||
*/
|
||||
public char colorChar() {
|
||||
return this.colorChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character to use as a special color code.
|
||||
* @param colorChar The character to be used as the color char (for legacy and MineDown colors, default: ampersand &)
|
||||
* @return The MineDownStringifier instance
|
||||
*/
|
||||
public MineDownStringifier colorChar(char colorChar) {
|
||||
this.colorChar = colorChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
package net.momirealms.customcrops.libs.minedown;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.ItemTag;
|
||||
import net.md_5.bungee.api.chat.KeybindComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Content;
|
||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This class offers the ability to replace placeholders with values in strings and components.
|
||||
* It also lets you define which placeholders indicators (prefix and suffix) should be used.
|
||||
* By default these are the % character.
|
||||
*/
|
||||
public class Replacer {
|
||||
|
||||
private static final boolean HAS_KEYBIND_SUPPORT = Util.hasClass("net.md_5.bungee.api.chat.KeybindComponent");
|
||||
private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
|
||||
private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
|
||||
private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
|
||||
|
||||
/**
|
||||
* A cache of compiled replacement patterns
|
||||
*/
|
||||
private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* The creator of the patterns for the pattern cache
|
||||
*/
|
||||
private static final Function<String, Pattern> PATTERN_CREATOR = p -> Pattern.compile(p, Pattern.LITERAL);
|
||||
|
||||
/**
|
||||
* The map of placeholders with their string replacements
|
||||
*/
|
||||
private final Map<String, String> replacements = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* The map of placeholders with their component array replacements
|
||||
*/
|
||||
private final Map<String, BaseComponent[]> componentReplacements = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* The placeholder indicator's prefix character
|
||||
*/
|
||||
private String placeholderPrefix = "%";
|
||||
|
||||
/**
|
||||
* The placeholder indicator's suffix character
|
||||
*/
|
||||
private String placeholderSuffix = "%";
|
||||
|
||||
/**
|
||||
* Replace the placeholder no matter what the case of it is
|
||||
*/
|
||||
private boolean ignorePlaceholderCase = true;
|
||||
|
||||
/**
|
||||
* Replace certain placeholders with values in string.
|
||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
||||
* @param message The string to replace in
|
||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
||||
* @return The string with all the placeholders replaced
|
||||
*/
|
||||
public static String replaceIn(String message, String... replacements) {
|
||||
return new Replacer().replace(replacements).replaceIn(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace certain placeholders with values in a component array.
|
||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
||||
* @param message The BaseComponent array to replace in
|
||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
||||
* @return A copy of the BaseComponent array with all the placeholders replaced
|
||||
*/
|
||||
public static BaseComponent[] replaceIn(BaseComponent[] message, String... replacements) {
|
||||
return new Replacer().replace(replacements).replaceIn(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a certain placeholder with a component array in a component array.
|
||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
||||
* @param message The BaseComponent array to replace in
|
||||
* @param placeholder The placeholder to replace
|
||||
* @param replacement The replacement components
|
||||
* @return A copy of the BaseComponent array with all the placeholders replaced
|
||||
*/
|
||||
public static BaseComponent[] replaceIn(BaseComponent[] message, String placeholder, BaseComponent... replacement) {
|
||||
return new Replacer().replace(placeholder, replacement).replaceIn(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array with placeholders and values that should get replaced in the message
|
||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public Replacer replace(String... replacements) {
|
||||
Util.validate(replacements.length % 2 == 0, "The replacement length has to be even, " +
|
||||
"mapping i % 2 == 0 to the placeholder and i % 2 = 1 to the placeholder's value");
|
||||
Map<String, String> replacementMap = new LinkedHashMap<>();
|
||||
for (int i = 0; i + 1 < replacements.length; i += 2) {
|
||||
replacementMap.put(replacements[i], replacements[i + 1]);
|
||||
}
|
||||
return replace(replacementMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a map with placeholders and values that should get replaced in the message
|
||||
* @param replacements The replacements mapped placeholder to value
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public Replacer replace(Map<String, ?> replacements) {
|
||||
if (replacements != null && !replacements.isEmpty()) {
|
||||
Object any = replacements.values().stream().filter(Objects::nonNull).findAny().orElse(null);
|
||||
if (any instanceof String) {
|
||||
replacements().putAll((Map<String, String>) replacements);
|
||||
} else if (any != null && any.getClass().isArray() && BaseComponent.class.isAssignableFrom(any.getClass().getComponentType())) {
|
||||
componentReplacements().putAll((Map<String, BaseComponent[]>) replacements);
|
||||
} else {
|
||||
for (Map.Entry<String, ?> entry : replacements.entrySet()) {
|
||||
replacements().put(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a placeholder to component mapping that should get replaced in the message
|
||||
* @param placeholder The placeholder to replace
|
||||
* @param replacement The replacement components
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public Replacer replace(String placeholder, BaseComponent... replacement) {
|
||||
componentReplacements().put(placeholder, replacement);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator for both prefix and suffix
|
||||
* @param placeholderIndicator The character to use as a placeholder indicator
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public Replacer placeholderIndicator(String placeholderIndicator) {
|
||||
placeholderPrefix(placeholderIndicator);
|
||||
placeholderSuffix(placeholderIndicator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in a component array
|
||||
* @param components The BaseComponent array to replace in
|
||||
* @return A copy of the array with the placeholders replaced
|
||||
*/
|
||||
public BaseComponent[] replaceIn(BaseComponent... components) {
|
||||
return replaceIn(Arrays.asList(components));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in a component list
|
||||
* @param components The BaseComponent list to replace in
|
||||
* @return A copy of the array with the placeholders replaced
|
||||
*/
|
||||
public BaseComponent[] replaceIn(List<BaseComponent> components) {
|
||||
List<BaseComponent> returnList = new ArrayList<>();
|
||||
// String replacements:
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
BaseComponent component = components.get(i).duplicate();
|
||||
if (HAS_KEYBIND_SUPPORT && component instanceof KeybindComponent) {
|
||||
((KeybindComponent) component).setKeybind(replaceIn(((KeybindComponent) component).getKeybind()));
|
||||
}
|
||||
if (component instanceof TextComponent) {
|
||||
String replaced = replaceIn(((TextComponent) component).getText());
|
||||
int sectionIndex = replaced.indexOf(ChatColor.COLOR_CHAR);
|
||||
if (sectionIndex > -1 && replaced.length() > sectionIndex + 1
|
||||
&& ChatColor.getByChar(replaced.charAt(sectionIndex + 1)) != null) {
|
||||
// replacement contain legacy code, parse to components and append them as extra
|
||||
BaseComponent[] replacedComponent = TextComponent.fromLegacyText(replaced);
|
||||
((TextComponent) component).setText("");
|
||||
List<BaseComponent> extra = new ArrayList<>();
|
||||
Collections.addAll(extra, replacedComponent);
|
||||
if (component.getExtra() != null) {
|
||||
Collections.addAll(extra, replaceIn(component.getExtra()));
|
||||
}
|
||||
component.setExtra(extra);
|
||||
} else {
|
||||
((TextComponent) component).setText(replaced);
|
||||
if (component.getExtra() != null) {
|
||||
component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
|
||||
}
|
||||
}
|
||||
} else if (component.getExtra() != null) {
|
||||
component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
|
||||
}
|
||||
if (component instanceof TranslatableComponent) {
|
||||
((TranslatableComponent) component).setTranslate(replaceIn(((TranslatableComponent) component).getTranslate()));
|
||||
((TranslatableComponent) component).setWith(Arrays.asList(replaceIn(((TranslatableComponent) component).getWith())));
|
||||
}
|
||||
if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
|
||||
component.setInsertion(replaceIn(component.getInsertion()));
|
||||
}
|
||||
if (component.getClickEvent() != null) {
|
||||
component.setClickEvent(new ClickEvent(
|
||||
component.getClickEvent().getAction(),
|
||||
replaceIn(component.getClickEvent().getValue())
|
||||
));
|
||||
}
|
||||
if (component.getHoverEvent() != null) {
|
||||
if (HAS_HOVER_CONTENT_SUPPORT) {
|
||||
component.setHoverEvent(new HoverEvent(
|
||||
component.getHoverEvent().getAction(),
|
||||
replaceInContents(component.getHoverEvent().getContents())
|
||||
));
|
||||
} else if (HOVER_GET_VALUE != null) {
|
||||
try {
|
||||
component.setHoverEvent(new HoverEvent(
|
||||
component.getHoverEvent().getAction(),
|
||||
replaceIn((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent()))
|
||||
));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component replacements
|
||||
List<BaseComponent> replacedComponents = new ArrayList<>();
|
||||
replacedComponents.add(component);
|
||||
|
||||
for (Map.Entry<String, BaseComponent[]> replacement : componentReplacements().entrySet()) {
|
||||
List<BaseComponent> newReplacedComponents = new ArrayList<>();
|
||||
|
||||
for (BaseComponent replaceComponent : replacedComponents) {
|
||||
if (replaceComponent instanceof TextComponent) {
|
||||
TextComponent textComponent = (TextComponent) replaceComponent;
|
||||
String placeHolder = placeholderPrefix()
|
||||
+ (ignorePlaceholderCase() ? replacement.getKey().toLowerCase(Locale.ROOT) : replacement.getKey())
|
||||
+ placeholderSuffix();
|
||||
String text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
|
||||
int index = text.indexOf(placeHolder);
|
||||
if (index > -1) {
|
||||
do {
|
||||
TextComponent startComponent = new TextComponent(textComponent);
|
||||
if (index > 0) {
|
||||
startComponent.setText(textComponent.getText().substring(0, index));
|
||||
} else {
|
||||
startComponent.setText("");
|
||||
}
|
||||
startComponent.setExtra(Arrays.asList(replacement.getValue()));
|
||||
newReplacedComponents.add(startComponent);
|
||||
|
||||
if (index + placeHolder.length() < textComponent.getText().length()) {
|
||||
textComponent.setText(textComponent.getText().substring(index + placeHolder.length()));
|
||||
} else {
|
||||
textComponent.setText("");
|
||||
}
|
||||
text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
|
||||
newReplacedComponents.add(textComponent);
|
||||
} while (!text.isEmpty() && (index = text.indexOf(placeHolder)) > -1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing was replaced, just add it
|
||||
newReplacedComponents.add(replaceComponent);
|
||||
}
|
||||
replacedComponents = newReplacedComponents;
|
||||
}
|
||||
returnList.addAll(replacedComponents);
|
||||
}
|
||||
return returnList.toArray(new BaseComponent[0]);
|
||||
}
|
||||
|
||||
private List<Content> replaceInContents(List<Content> contents) {
|
||||
List<Content> replacedContents = new ArrayList<>();
|
||||
for (Content content : contents) {
|
||||
if (content instanceof Text) {
|
||||
Object value = ((Text) content).getValue();
|
||||
if (value instanceof BaseComponent[]) {
|
||||
replacedContents.add(new Text(replaceIn((BaseComponent[]) value)));
|
||||
} else if (value instanceof String) {
|
||||
replacedContents.add(new Text(replaceIn((String) value)));
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot replace in " + value.getClass() + "!");
|
||||
}
|
||||
} else if (content instanceof Entity) {
|
||||
Entity entity = (Entity) content;
|
||||
String id = replaceIn(entity.getId());
|
||||
String type;
|
||||
if (entity.getType() != null) {
|
||||
type = replaceIn(entity.getType());
|
||||
} else {
|
||||
type = "minecraft:pig"; // Meh
|
||||
}
|
||||
BaseComponent name = null;
|
||||
if (entity.getName() != null) {
|
||||
name = new TextComponent(replaceIn(TextComponent.toLegacyText(entity.getName())));
|
||||
}
|
||||
replacedContents.add(new Entity(type, id, name));
|
||||
} else if (content instanceof Item) {
|
||||
Item item = (Item) content;
|
||||
String id = replaceIn(item.getId());
|
||||
ItemTag itemTag = item.getTag() != null ? ItemTag.ofNbt(replaceIn(item.getTag().getNbt())) : null;
|
||||
replacedContents.add(new Item(id, item.getCount(), itemTag));
|
||||
} else {
|
||||
replacedContents.add(content); // TODO: Find a good way to clone this
|
||||
}
|
||||
}
|
||||
return replacedContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in a string. Does not replace component replacements!
|
||||
* @param string The String list to replace in
|
||||
* @return The string with the placeholders replaced
|
||||
*/
|
||||
public String replaceIn(String string) {
|
||||
for (Map.Entry<String, String> replacement : replacements().entrySet()) {
|
||||
String replValue = replacement.getValue() != null ? replacement.getValue() : "null";
|
||||
if (ignorePlaceholderCase()) {
|
||||
String placeholder = placeholderPrefix() + replacement.getKey().toLowerCase(Locale.ROOT) + placeholderSuffix();
|
||||
int nextStart = 0;
|
||||
int startIndex;
|
||||
while (nextStart < string.length() && (startIndex = string.toLowerCase(Locale.ROOT).indexOf(placeholder, nextStart)) > -1) {
|
||||
nextStart = startIndex + replValue.length();
|
||||
string = string.substring(0, startIndex) + replValue + string.substring(startIndex + placeholder.length());
|
||||
}
|
||||
} else {
|
||||
String placeholder = placeholderPrefix() + replacement.getKey() + placeholderSuffix();
|
||||
Pattern pattern = PATTERN_CACHE.computeIfAbsent(placeholder, PATTERN_CREATOR);
|
||||
string = pattern.matcher(string).replaceAll(Matcher.quoteReplacement(replValue));
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this Replacer
|
||||
* @return A copy of this Replacer
|
||||
*/
|
||||
public Replacer copy() {
|
||||
return new Replacer().copy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the values of another Replacer
|
||||
* @param from The replacer to copy
|
||||
* @return The Replacer instance
|
||||
*/
|
||||
public Replacer copy(Replacer from) {
|
||||
replacements().clear();
|
||||
replacements().putAll(from.replacements());
|
||||
componentReplacements().clear();
|
||||
componentReplacements().putAll(from.componentReplacements());
|
||||
placeholderPrefix(from.placeholderPrefix());
|
||||
placeholderSuffix(from.placeholderSuffix());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of placeholders with their string replacements
|
||||
* @return the replacement map
|
||||
*/
|
||||
public Map<String, String> replacements() {
|
||||
return this.replacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of placeholders with their component array replacements
|
||||
* @return the replacement map
|
||||
*/
|
||||
public Map<String, BaseComponent[]> componentReplacements() {
|
||||
return this.componentReplacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the placeholder indicator's prefix string
|
||||
* @return the prefix characters
|
||||
*/
|
||||
public String placeholderPrefix() {
|
||||
return this.placeholderPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator's prefix string
|
||||
* @param placeholderPrefix The placeholder prefix string
|
||||
* @return the instance of this Replacer
|
||||
*/
|
||||
public Replacer placeholderPrefix(String placeholderPrefix) {
|
||||
this.placeholderPrefix = placeholderPrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the placeholder indicator's suffix string
|
||||
* @return the suffix characters
|
||||
*/
|
||||
public String placeholderSuffix() {
|
||||
return this.placeholderSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the placeholder indicator's suffix string
|
||||
* @param placeholderSuffix The placeholder suffix string
|
||||
* @return the instance of this Replacer
|
||||
*/
|
||||
public Replacer placeholderSuffix(String placeholderSuffix) {
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholder no matter what the case of it is
|
||||
* @return whether or not to ignore the placeholder case (Default: true)
|
||||
*/
|
||||
public boolean ignorePlaceholderCase() {
|
||||
return this.ignorePlaceholderCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the placeholder should be replaced no matter what the case of it is
|
||||
* @param ignorePlaceholderCase Whether or not to ignore the case in placeholders (Default: true)
|
||||
* @return the instance of this Replacer
|
||||
*/
|
||||
public Replacer ignorePlaceholderCase(boolean ignorePlaceholderCase) {
|
||||
this.ignorePlaceholderCase = ignorePlaceholderCase;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,590 +0,0 @@
|
||||
package net.momirealms.customcrops.libs.minedown;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Util {
|
||||
|
||||
private static final Pattern WRAP_PATTERN = Pattern.compile(" ", Pattern.LITERAL);
|
||||
|
||||
/**
|
||||
* Utility method to throw an IllegalArgumentException if the value is false
|
||||
* @param value The value to validate
|
||||
* @param message The message for the exception
|
||||
* @throws IllegalArgumentException Thrown if the value is false
|
||||
*/
|
||||
public static void validate(boolean value, String message) throws IllegalArgumentException {
|
||||
if (!value) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a collection of colors/formats to a component
|
||||
* @param component The BaseComponent
|
||||
* @param formats The collection of ChatColor formats to apply
|
||||
* @return The component that was modified
|
||||
*/
|
||||
public static BaseComponent applyFormat(BaseComponent component, Collection<ChatColor> formats) {
|
||||
for (ChatColor format : formats) {
|
||||
if (format == ChatColor.BOLD) {
|
||||
component.setBold(true);
|
||||
} else if (format == ChatColor.ITALIC) {
|
||||
component.setItalic(true);
|
||||
} else if (format == ChatColor.UNDERLINE) {
|
||||
component.setUnderlined(true);
|
||||
} else if (format == ChatColor.STRIKETHROUGH) {
|
||||
component.setStrikethrough(true);
|
||||
} else if (format == ChatColor.MAGIC) {
|
||||
component.setObfuscated(true);
|
||||
} else if (format == ChatColor.RESET) {
|
||||
component.setBold(false);
|
||||
component.setItalic(false);
|
||||
component.setUnderlined(false);
|
||||
component.setStrikethrough(false);
|
||||
component.setObfuscated(false);
|
||||
component.setColor(ChatColor.WHITE);
|
||||
} else {
|
||||
component.setColor(format);
|
||||
}
|
||||
}
|
||||
if (component.getExtra() != null) {
|
||||
for (BaseComponent extra : component.getExtra()) {
|
||||
applyFormat(extra, formats);
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a collection of colors/formats to a component builder
|
||||
* @param builder The ComponentBuilder
|
||||
* @param formats The collection of ChatColor formats to apply
|
||||
* @return The component builder that was modified
|
||||
* @deprecated Use {@link #applyFormat(BaseComponent, Collection)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ComponentBuilder applyFormat(ComponentBuilder builder, Set<ChatColor> formats) {
|
||||
Map<ChatColor, Boolean> formatMap = new HashMap<>();
|
||||
for (ChatColor format : formats) {
|
||||
formatMap.put(format, true);
|
||||
}
|
||||
return applyFormat(builder, formatMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a collection of colors/formats to a component builder
|
||||
* @param builder The ComponentBuilder
|
||||
* @param formats The collection of ChatColor formats to apply
|
||||
* @return The component builder that was modified
|
||||
*/
|
||||
public static ComponentBuilder applyFormat(ComponentBuilder builder, Map<ChatColor, Boolean> formats) {
|
||||
for (Map.Entry<ChatColor, Boolean> e : formats.entrySet()) {
|
||||
if (e.getKey() == ChatColor.BOLD) {
|
||||
builder.bold(e.getValue());
|
||||
} else if (e.getKey() == ChatColor.ITALIC) {
|
||||
builder.italic(e.getValue());
|
||||
} else if (e.getKey() == ChatColor.UNDERLINE) {
|
||||
builder.underlined(e.getValue());
|
||||
} else if (e.getKey() == ChatColor.STRIKETHROUGH) {
|
||||
builder.strikethrough(e.getValue());
|
||||
} else if (e.getKey() == ChatColor.MAGIC) {
|
||||
builder.obfuscated(e.getValue());
|
||||
} else if (e.getKey() == ChatColor.RESET) {
|
||||
builder.bold(!e.getValue());
|
||||
builder.italic(!e.getValue());
|
||||
builder.underlined(!e.getValue());
|
||||
builder.strikethrough(!e.getValue());
|
||||
builder.obfuscated(!e.getValue());
|
||||
builder.color(ChatColor.WHITE);
|
||||
} else if (e.getValue()) {
|
||||
builder.color(e.getKey());
|
||||
} else if (builder.getCurrentComponent().getColor() == e.getKey()) {
|
||||
builder.color(null);
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not a character at a certain index of a string repeats itself
|
||||
* @param string The string to check
|
||||
* @param index The index at which to check the character
|
||||
* @return Whether or not the character at that index repeated itself
|
||||
*/
|
||||
public static boolean isDouble(String string, int index) {
|
||||
return index + 1 < string.length() && string.charAt(index) == string.charAt(index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a certain ChatColor is formatting or not
|
||||
* @param format The ChatColor to check
|
||||
* @return <code>true</code> if it's a format, <code>false</code> if it's a color
|
||||
*/
|
||||
public static boolean isFormat(ChatColor format) {
|
||||
return !MineDown.getFormatString(format).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of ChatColor formats all formats that a component includes
|
||||
* @param component The component to get the formats from
|
||||
* @param ignoreParent Whether or not to include the parent's format
|
||||
* @return A set of all the format ChatColors that the component includes
|
||||
*/
|
||||
public static Set<ChatColor> getFormats(BaseComponent component, boolean ignoreParent) {
|
||||
Set<ChatColor> formats = new LinkedHashSet<>();
|
||||
if ((!ignoreParent && component.isBold()) || (component.isBoldRaw() != null && component.isBoldRaw())) {
|
||||
formats.add(ChatColor.BOLD);
|
||||
}
|
||||
if ((!ignoreParent && component.isItalic()) || (component.isItalicRaw() != null && component.isItalicRaw())) {
|
||||
formats.add(ChatColor.ITALIC);
|
||||
}
|
||||
if ((!ignoreParent && component.isUnderlined()) || (component.isUnderlinedRaw() != null && component.isUnderlinedRaw())) {
|
||||
formats.add(ChatColor.UNDERLINE);
|
||||
}
|
||||
if ((!ignoreParent && component.isStrikethrough()) || (component.isStrikethroughRaw() != null && component.isStrikethroughRaw())) {
|
||||
formats.add(ChatColor.STRIKETHROUGH);
|
||||
}
|
||||
if ((!ignoreParent && component.isObfuscated()) || (component.isObfuscatedRaw() != null && component.isObfuscatedRaw())) {
|
||||
formats.add(ChatColor.MAGIC);
|
||||
}
|
||||
return formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the first occurrences of a not escaped character
|
||||
* @param string The string to search
|
||||
* @param chars The characters to search for
|
||||
* @return The first unescaped index or -1 if not found
|
||||
*/
|
||||
public static int indexOfNotEscaped(String string, String chars) {
|
||||
return indexOfNotEscaped(string, chars, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the first occurrences of a not escaped character
|
||||
* @param string The string to search
|
||||
* @param chars The characters to search for
|
||||
* @param fromIndex Start searching from that index
|
||||
* @return The first unescaped index or {@code -1} if not found
|
||||
*/
|
||||
public static int indexOfNotEscaped(String string, String chars, int fromIndex) {
|
||||
for (int i = fromIndex; i < string.length(); i++) {
|
||||
int index = string.indexOf(chars, i);
|
||||
if (index == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (!isEscaped(string, index)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a character at a certain index is escaped
|
||||
* @param string The string to check
|
||||
* @param index The index of the character in the string to check
|
||||
* @return Whether or not the character is escaped (uneven number of backslashes in front of char mains it is escaped)
|
||||
* @throws IndexOutOfBoundsException if the {@code index} argument is not less than the length of this string.
|
||||
*/
|
||||
public static boolean isEscaped(String string, int index) {
|
||||
if (index - 1 > string.length()) {
|
||||
return false;
|
||||
}
|
||||
int e = 0;
|
||||
while (index > e && string.charAt(index - e - 1) == '\\') {
|
||||
e++;
|
||||
}
|
||||
return e % 2 != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a string if it is longer than the line length and contains no new line.
|
||||
* Will try to wrap at spaces between words.
|
||||
* @param string The string to wrap
|
||||
* @param lineLength The max length of a line
|
||||
* @return The wrapped string
|
||||
*/
|
||||
public static String wrap(String string, int lineLength) {
|
||||
if (string.length() <= lineLength || string.contains("\n")) {
|
||||
return string;
|
||||
}
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
StringBuilder currentLine = new StringBuilder();
|
||||
for (String s : WRAP_PATTERN.split(string)) {
|
||||
if (currentLine.length() + s.length() + 1 > lineLength) {
|
||||
int rest = lineLength - currentLine.length() - 1;
|
||||
if (rest > lineLength / 4 && s.length() > Math.min(rest * 2, lineLength / 4)) {
|
||||
currentLine.append(" ").append(s, 0, rest);
|
||||
} else {
|
||||
rest = 0;
|
||||
}
|
||||
lines.add(currentLine.toString());
|
||||
String restString = s.substring(rest);
|
||||
while (restString.length() >= lineLength) {
|
||||
lines.add(restString.substring(0, lineLength));
|
||||
restString = restString.substring(lineLength);
|
||||
}
|
||||
currentLine = new StringBuilder(restString);
|
||||
} else {
|
||||
if (currentLine.length() > 0) {
|
||||
currentLine.append(" ");
|
||||
}
|
||||
currentLine.append(s);
|
||||
}
|
||||
}
|
||||
if (currentLine.length() > 0) {
|
||||
lines.add(currentLine.toString());
|
||||
}
|
||||
return String.join("\n", lines);
|
||||
}
|
||||
|
||||
private static Map<ChatColor, Color> legacyColors = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
legacyColors.put(ChatColor.BLACK, new Color(0x000000));
|
||||
legacyColors.put(ChatColor.DARK_BLUE, new Color(0x0000AA));
|
||||
legacyColors.put(ChatColor.DARK_GREEN, new Color(0x00AA00));
|
||||
legacyColors.put(ChatColor.DARK_AQUA, new Color(0x00AAAA));
|
||||
legacyColors.put(ChatColor.DARK_RED, new Color(0xAA0000));
|
||||
legacyColors.put(ChatColor.DARK_PURPLE, new Color(0xAA00AA));
|
||||
legacyColors.put(ChatColor.GOLD, new Color(0xFFAA00));
|
||||
legacyColors.put(ChatColor.GRAY, new Color(0xAAAAAA));
|
||||
legacyColors.put(ChatColor.DARK_GRAY, new Color(0x555555));
|
||||
legacyColors.put(ChatColor.BLUE, new Color(0x05555FF));
|
||||
legacyColors.put(ChatColor.GREEN, new Color(0x55FF55));
|
||||
legacyColors.put(ChatColor.AQUA, new Color(0x55FFFF));
|
||||
legacyColors.put(ChatColor.RED, new Color(0xFF5555));
|
||||
legacyColors.put(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF));
|
||||
legacyColors.put(ChatColor.YELLOW, new Color(0xFFFF55));
|
||||
legacyColors.put(ChatColor.WHITE, new Color(0xFFFFFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to remove RGB colors from components. This modifies the input array!
|
||||
* @param components The components to remove the rgb colors from
|
||||
* @return The modified components (same as input).
|
||||
*/
|
||||
public static BaseComponent[] rgbColorsToLegacy(BaseComponent[] components) {
|
||||
for (BaseComponent component : components) {
|
||||
if (component.getColorRaw() != null && component.getColorRaw().getName().startsWith("#")) {
|
||||
component.setColor(getClosestLegacy(new Color(Integer.parseInt(component.getColorRaw().getName().substring(1), 16))));
|
||||
}
|
||||
if (component.getExtra() != null) {
|
||||
rgbColorsToLegacy(component.getExtra().toArray(new BaseComponent[0]));
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy color closest to a certain RGB color
|
||||
* @param color The color to get the closest legacy color for
|
||||
* @return The closest legacy color
|
||||
*/
|
||||
public static ChatColor getClosestLegacy(Color color) {
|
||||
ChatColor closest = null;
|
||||
double smallestDistance = Double.MAX_VALUE;
|
||||
for (Map.Entry<ChatColor, Color> legacy : legacyColors.entrySet()) {
|
||||
double distance = distance(color, legacy.getValue());
|
||||
if (distance < smallestDistance) {
|
||||
smallestDistance = distance;
|
||||
closest = legacy.getKey();
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance between two colors
|
||||
* @param c1 Color A
|
||||
* @param c2 Color B
|
||||
* @return The distance or 0 if they are equal
|
||||
*/
|
||||
public static double distance(Color c1, Color c2) {
|
||||
if (c1.getRGB() == c2.getRGB()) {
|
||||
return 0;
|
||||
}
|
||||
return Math.sqrt(Math.pow(c1.getRed() - c2.getRed(), 2) + Math.pow(c1.getGreen() - c2.getGreen(), 2) + Math.pow(c1.getBlue() - c2.getBlue(), 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* createRainbow is adapted from the net.kyori.adventure.text.minimessage.fancy.Rainbow class
|
||||
* in adventure-text-minimessage, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2018-2020 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* Generate a rainbow with a certain length and phase
|
||||
* @param length The length of the rainbow
|
||||
* @param phase The phase of the rainbow.
|
||||
* @param rgb Whether or not to use RGB colors
|
||||
* @return the colors in the rainbow
|
||||
* @deprecated Use {@link #createRainbow(long, int, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<ChatColor> createRainbow(int length, int phase, boolean rgb) {
|
||||
return createRainbow((long) length, phase, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a rainbow with a certain length and phase
|
||||
* @param length The length of the rainbow
|
||||
* @param phase The phase of the rainbow.
|
||||
* @param rgb Whether or not to use RGB colors
|
||||
* @return the colors in the rainbow
|
||||
*/
|
||||
public static List<ChatColor> createRainbow(long length, int phase, boolean rgb) {
|
||||
List<ChatColor> colors = new ArrayList<>();
|
||||
|
||||
float fPhase = phase / 10f;
|
||||
|
||||
float center = 128;
|
||||
float width = 127;
|
||||
double frequency = Math.PI * 2 / length;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Color color = new Color(
|
||||
(int) (Math.sin(frequency * i + 2 + fPhase) * width + center),
|
||||
(int) (Math.sin(frequency * i + 0 + fPhase) * width + center),
|
||||
(int) (Math.sin(frequency * i + 4 + fPhase) * width + center)
|
||||
);
|
||||
if (rgb) {
|
||||
colors.add(ChatColor.of(color));
|
||||
} else {
|
||||
ChatColor chatColor = getClosestLegacy(color);
|
||||
if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
|
||||
colors.add(chatColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
/*
|
||||
* createGradient is adapted from the net.kyori.adventure.text.minimessage.fancy.Gradient class
|
||||
* in adventure-text-minimessage, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2018-2020 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* Generate a gradient with certain colors
|
||||
* @param length The length of the gradient
|
||||
* @param gradient The colors of the gradient.
|
||||
* @param rgb Whether or not to use RGB colors
|
||||
* @return the colors in the gradient
|
||||
* @deprecated Use {@link #createRainbow(long, int, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<ChatColor> createGradient(int length, List<ChatColor> gradient, boolean rgb) {
|
||||
return createGradient((long) length, gradient, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a gradient with certain colors
|
||||
* @param length The length of the gradient
|
||||
* @param gradient The colors of the gradient.
|
||||
* @param rgb Whether or not to use RGB colors
|
||||
* @return the colors in the gradient
|
||||
*/
|
||||
public static List<ChatColor> createGradient(long length, List<ChatColor> gradient, boolean rgb) {
|
||||
List<ChatColor> colors = new ArrayList<>();
|
||||
if (gradient.size() < 2 || length < 2) {
|
||||
if (gradient.isEmpty()) {
|
||||
return gradient;
|
||||
}
|
||||
return Collections.singletonList(gradient.get(0));
|
||||
}
|
||||
|
||||
float fPhase = 0;
|
||||
|
||||
float sectorLength = (float) (length - 1) / (gradient.size() - 1);
|
||||
float factorStep = 1.0f / (sectorLength);
|
||||
|
||||
long index = 0;
|
||||
|
||||
int colorIndex = 0;
|
||||
|
||||
for (long i = 0; i < length; i++) {
|
||||
|
||||
if (factorStep * index > 1) {
|
||||
colorIndex++;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
float factor = factorStep * (index++ + fPhase);
|
||||
// loop around if needed
|
||||
if (factor > 1) {
|
||||
factor = 1 - (factor - 1);
|
||||
}
|
||||
|
||||
Color color = interpolate(
|
||||
getColor(gradient.get(colorIndex), rgb),
|
||||
getColor(gradient.get(Math.min(gradient.size() - 1, colorIndex + 1)), rgb),
|
||||
factor
|
||||
);
|
||||
|
||||
if (color != null) {
|
||||
if (rgb) {
|
||||
colors.add(ChatColor.of(color));
|
||||
} else {
|
||||
ChatColor chatColor = getClosestLegacy(color);
|
||||
if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
|
||||
colors.add(chatColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
private static Color getColor(ChatColor color, boolean rgb) {
|
||||
if (legacyColors.containsKey(color)) {
|
||||
return legacyColors.get(color);
|
||||
}
|
||||
|
||||
if (color.getName().startsWith("#")) {
|
||||
Color c = new Color(Integer.parseInt(color.getName().substring(1), 16));
|
||||
if (rgb) {
|
||||
return c;
|
||||
} else {
|
||||
return legacyColors.get(getClosestLegacy(c));
|
||||
}
|
||||
} else if (rgb) {
|
||||
return color.getColor();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Color interpolate(Color color1, Color color2, float factor) {
|
||||
if (color1 == null || color2 == null) {
|
||||
return null;
|
||||
}
|
||||
return new Color(
|
||||
Math.round(color1.getRed() + factor * (color2.getRed() - color1.getRed())),
|
||||
Math.round(color1.getGreen() + factor * (color2.getGreen() - color1.getGreen())),
|
||||
Math.round(color1.getBlue() + factor * (color2.getBlue() - color1.getBlue()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain class exists. See {@link Class#forName(String)}
|
||||
* @param className The class name to check
|
||||
* @return <code>true</code> if the class exists, <code>false</code> if not
|
||||
*/
|
||||
public static boolean hasClass(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException classDoesntExist) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a class has a certain method. See {@link Class#getMethod(String, Class[])}
|
||||
* @param clazz The class to check
|
||||
* @param method The method to check for
|
||||
* @param parameter Method parameter types
|
||||
* @return <code>true</code> if the class has the method, <code>false</code> if not
|
||||
*/
|
||||
public static boolean hasMethod(Class<?> clazz, String method, Class<?>... parameter) {
|
||||
try {
|
||||
clazz.getMethod(method, parameter);
|
||||
return true;
|
||||
} catch (NoSuchMethodException methodDoesntExist) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a method from a class if it exists. See {@link Class#getMethod(String, Class[])}
|
||||
* @param clazz The class
|
||||
* @param method The method name to get
|
||||
* @param parameter Method parameter types
|
||||
* @return the method, null if it doesn't exist
|
||||
*/
|
||||
public static Method getMethod(Class<?> clazz, String method, Class<?>... parameter) {
|
||||
try {
|
||||
return clazz.getMethod(method, parameter);
|
||||
} catch (NoSuchMethodException methodDoesntExist) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.momirealms.customcrops.limits;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class CropsPerChunk {
|
||||
|
||||
public static boolean isLimited(Location location){
|
||||
if(!ConfigReader.Config.enableLimit){
|
||||
return false;
|
||||
}
|
||||
int n = 1;
|
||||
Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,ConfigReader.Config.yMin,location.getChunk().getZ()*16);
|
||||
Label_out:
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
Location square = chunkLocation.clone().add(i, 0.0, j);
|
||||
for (int k = ConfigReader.Config.yMin; k <= ConfigReader.Config.yMax; ++k) {
|
||||
square.add(0.0, 1.0, 0.0);
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(square.getBlock());
|
||||
if(customBlock != null){
|
||||
if (customBlock.getNamespacedID().contains("_stage_")) {
|
||||
if (n++ > ConfigReader.Config.cropLimit) {
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return n > ConfigReader.Config.cropLimit;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package net.momirealms.customcrops.limits;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class MaxCropsPerChunk {
|
||||
|
||||
public static boolean maxCropsPerChunk(Location location){
|
||||
|
||||
if(!ConfigManager.Config.limit){
|
||||
return false;
|
||||
}
|
||||
int maxY = ConfigManager.Config.maxh;
|
||||
int minY = ConfigManager.Config.minh;
|
||||
int maxAmount = ConfigManager.Config.max_crop;
|
||||
|
||||
int n = 1;
|
||||
|
||||
Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,minY,location.getChunk().getZ()*16);
|
||||
|
||||
Label_out:
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
Location square = chunkLocation.clone().add(i, 0.0, j);
|
||||
for (int k = minY; k <= maxY; ++k) {
|
||||
square.add(0.0, 1.0, 0.0);
|
||||
Block b = square.getBlock();
|
||||
if(CustomBlock.byAlreadyPlaced(b)!= null){
|
||||
if (CustomBlock.byAlreadyPlaced(b).getNamespacedID().contains("_stage_")) {
|
||||
if (n++ > maxAmount) {
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return n > maxAmount;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,33 @@
|
||||
package net.momirealms.customcrops.limits;
|
||||
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.utils.IAFurniture;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class MaxSprinklersPerChunk {
|
||||
public class SprinklersPerChunk {
|
||||
|
||||
public static boolean maxSprinklersPerChunk(Location location){
|
||||
|
||||
if(!ConfigManager.Config.limit){
|
||||
public static boolean isLimited(Location location){
|
||||
if(!ConfigReader.Config.enableLimit){
|
||||
return false;
|
||||
}
|
||||
int maxY = ConfigManager.Config.maxh;
|
||||
int minY = ConfigManager.Config.minh;
|
||||
int maxAmount = ConfigManager.Config.max_sprinkler;
|
||||
|
||||
int n = 1;
|
||||
|
||||
Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,minY,location.getChunk().getZ()*16);
|
||||
Location chunkLocation = new Location(location.getWorld(),location.getChunk().getX()*16,ConfigReader.Config.yMin,location.getChunk().getZ()*16);
|
||||
World world = location.getWorld();
|
||||
|
||||
Label_out:
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
Location square = chunkLocation.clone().add(i+0.5, 0.5, j+0.5);
|
||||
for (int k = minY; k <= maxY; ++k) {
|
||||
Location square = chunkLocation.clone().add(i + 0.5, 0.5, j + 0.5);
|
||||
for (int k = ConfigReader.Config.yMin; k <= ConfigReader.Config.yMax; ++k) {
|
||||
square.add(0.0, 1.0, 0.0);
|
||||
if(IAFurniture.getFromLocation(square, world)){
|
||||
if (n++ > maxAmount) {
|
||||
if (n++ > ConfigReader.Config.sprinklerLimit) {
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return n > maxAmount;
|
||||
return n > ConfigReader.Config.sprinklerLimit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import dev.lone.itemsadder.api.Events.CustomBlockBreakEvent;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.datamanager.PotManager;
|
||||
import net.momirealms.customcrops.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.fertilizer.QualityCrop;
|
||||
import net.momirealms.customcrops.utils.CropInstance;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class BreakBlock implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onBreak(CustomBlockBreakEvent event){
|
||||
String namespacedId = event.getNamespacedID();
|
||||
if(namespacedId.contains("_stage_")){
|
||||
Player player =event.getPlayer();
|
||||
if(player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH) || player.getInventory().getItemInMainHand().getType() == Material.SHEARS){
|
||||
event.setCancelled(true);
|
||||
Location location = event.getBlock().getLocation();
|
||||
CustomBlock.place(namespacedId, location);
|
||||
CustomBlock.byAlreadyPlaced(location.getBlock()).getLoot().forEach(itemStack -> {
|
||||
location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
|
||||
});
|
||||
CustomBlock.remove(location);
|
||||
return;
|
||||
}
|
||||
if(ConfigReader.Config.quality && namespacedId.equals(ConfigReader.Basic.dead)) return;
|
||||
String[] cropNameList = StringUtils.split(StringUtils.split(namespacedId, ":")[1], "_");
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
if (CustomBlock.getInstance(StringUtils.chop(namespacedId) + nextStage) == null) {
|
||||
CropInstance cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
|
||||
ThreadLocalRandom current = ThreadLocalRandom.current();
|
||||
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
|
||||
Location location = event.getBlock().getLocation();
|
||||
Location itemLoc = location.clone().add(0.5,0.2,0.5);
|
||||
World world = location.getWorld();
|
||||
Fertilizer fertilizer = PotManager.Cache.get(location.clone().subtract(0,1,0));
|
||||
if (fertilizer != null){
|
||||
if (fertilizer instanceof QualityCrop qualityCrop){
|
||||
int[] weights = qualityCrop.getChance();
|
||||
double weightTotal = weights[0] + weights[1] + weights[2];
|
||||
double rank_1 = weights[0]/(weightTotal);
|
||||
double rank_2 = 1 - weights[1]/(weightTotal);
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < rank_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > rank_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < ConfigReader.Config.quality_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > ConfigReader.Config.quality_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(namespacedId.equalsIgnoreCase(ConfigReader.Basic.watered_pot) || namespacedId.equalsIgnoreCase(ConfigReader.Basic.pot)){
|
||||
Location location = event.getBlock().getLocation();
|
||||
PotManager.Cache.remove(location);
|
||||
World world = location.getWorld();
|
||||
Block blockUp = location.add(0,1,0).getBlock();
|
||||
if(CustomBlock.byAlreadyPlaced(blockUp) != null){
|
||||
String cropNamespacedId = CustomBlock.byAlreadyPlaced(blockUp).getNamespacedID();
|
||||
if(cropNamespacedId.contains("_stage_")){
|
||||
CustomBlock.remove(location);
|
||||
if (cropNamespacedId.equals(ConfigReader.Basic.dead)) return;
|
||||
if(ConfigReader.Config.quality){
|
||||
String[] cropNameList = StringUtils.split(StringUtils.split(cropNamespacedId, ":")[1], "_");
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
if (CustomBlock.getInstance(StringUtils.chop(cropNamespacedId) + nextStage) == null) {
|
||||
CropInstance cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
|
||||
ThreadLocalRandom current = ThreadLocalRandom.current();
|
||||
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
|
||||
location.add(0,1,0);
|
||||
Location itemLoc = location.clone().add(0.5,0.2,0.5);
|
||||
Fertilizer fertilizer = PotManager.Cache.get(location.clone().subtract(0,1,0));
|
||||
if (fertilizer != null){
|
||||
if (fertilizer instanceof QualityCrop qualityCrop){
|
||||
int[] weights = qualityCrop.getChance();
|
||||
double weightTotal = weights[0] + weights[1] + weights[2];
|
||||
double rank_1 = weights[0]/(weightTotal);
|
||||
double rank_2 = 1 - weights[1]/(weightTotal);
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < rank_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > rank_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < ConfigReader.Config.quality_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > ConfigReader.Config.quality_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (ItemStack itemStack : CustomBlock.byAlreadyPlaced(blockUp).getLoot()) {
|
||||
world.dropItem(location.clone().add(0.5, 0.2, 0.5), itemStack);
|
||||
}
|
||||
CustomBlock.remove(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||
|
||||
public class BreakCrops implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void breakCrops(EntitySpawnEvent event){
|
||||
Entity entity = event.getEntity();
|
||||
if(!(entity instanceof Item)) return;
|
||||
if(CustomStack.byItemStack(((Item) entity).getItemStack()) != null){
|
||||
String namespacedId = CustomStack.byItemStack(((Item) entity).getItemStack()).getNamespacedID();
|
||||
if(namespacedId.equalsIgnoreCase(ConfigManager.Config.sprinkler_1)){
|
||||
entity.remove();
|
||||
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(ConfigManager.Config.sprinkler_1i).getItemStack());
|
||||
}else if(namespacedId.equalsIgnoreCase(ConfigManager.Config.sprinkler_2)){
|
||||
entity.remove();
|
||||
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(ConfigManager.Config.sprinkler_2i).getItemStack());
|
||||
}else if(namespacedId.contains("_stage_")){
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.Events.CustomBlockBreakEvent;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class BreakCustomBlock implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void breakCustomBlock(CustomBlockBreakEvent event){
|
||||
|
||||
String namespacedId = event.getNamespacedID();
|
||||
|
||||
//用于防止玩家使用精准采集获取生长阶段物品
|
||||
if(namespacedId.contains("_stage_")){
|
||||
Player player =event.getPlayer();
|
||||
if(player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH) || player.getInventory().getItemInMainHand().getType() == Material.SHEARS){
|
||||
event.setCancelled(true);
|
||||
Location location = event.getBlock().getLocation();
|
||||
CustomBlock.place(namespacedId, location);
|
||||
CustomBlock.byAlreadyPlaced(location.getBlock()).getLoot().forEach(itemStack -> {
|
||||
location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
|
||||
CustomBlock.remove(location);
|
||||
});
|
||||
}
|
||||
}
|
||||
//玩家破坏种植盆也会使得农作物掉落
|
||||
else if(namespacedId.equalsIgnoreCase(ConfigManager.Config.watered_pot) || namespacedId.equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
Location location = event.getBlock().getLocation();
|
||||
World world = location.getWorld();
|
||||
Block blockUp = location.add(0,1,0).getBlock();
|
||||
if(CustomBlock.byAlreadyPlaced(blockUp) != null){
|
||||
if(CustomBlock.byAlreadyPlaced(blockUp).getNamespacedID().contains("_stage_")){
|
||||
for (ItemStack itemStack : CustomBlock.byAlreadyPlaced(blockUp).getLoot()) {
|
||||
world.dropItem(location.clone().add(0.5, 0.2, 0.5), itemStack);
|
||||
}
|
||||
CustomBlock.remove(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomFurniture;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.datamanager.SprinklerManager;
|
||||
import net.momirealms.customcrops.utils.HoloUtil;
|
||||
import net.momirealms.customcrops.utils.Sprinkler;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class InteractEntity implements Listener {
|
||||
|
||||
private final CustomCrops plugin;
|
||||
private final HashMap<Player, Long> coolDown = new HashMap<>();
|
||||
|
||||
public InteractEntity(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityInteract(PlayerInteractAtEntityEvent event){
|
||||
Entity entity = event.getRightClicked();
|
||||
if(entity instanceof ArmorStand armorStand){
|
||||
if(CustomFurniture.byAlreadySpawned(armorStand) == null) return;
|
||||
Sprinkler config = ConfigReader.SPRINKLERS.get(CustomFurniture.byAlreadySpawned(armorStand).getId());
|
||||
if(config != null){
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
if (time - (coolDown.getOrDefault(player, time - 1000)) < 1000) {
|
||||
return;
|
||||
}
|
||||
coolDown.put(player, time);
|
||||
ItemStack itemStack = player.getInventory().getItemInMainHand();
|
||||
Location location = armorStand.getLocation();
|
||||
String world = location.getWorld().getName();
|
||||
int x = location.getBlockX();
|
||||
int z = location.getBlockZ();
|
||||
int maxWater = config.getWater();
|
||||
int currentWater = 0;
|
||||
if (itemStack.getType() == Material.WATER_BUCKET){
|
||||
itemStack.setType(Material.BUCKET);
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ITEM_BUCKET_FILL,1,1);
|
||||
Location loc = location.subtract(0,1,0).getBlock().getLocation().add(0,1,0);
|
||||
Sprinkler sprinkler = SprinklerManager.Cache.get(loc);
|
||||
if (sprinkler != null){
|
||||
currentWater = sprinkler.getWater();
|
||||
currentWater += ConfigReader.Config.sprinklerRefill;
|
||||
if (currentWater > maxWater){
|
||||
currentWater = maxWater;
|
||||
}
|
||||
sprinkler.setWater(currentWater);
|
||||
}else {
|
||||
StringBuilder stringBuilder = new StringBuilder().append(world).append(".").append(x/16).append(",").append(z/16).append(".").append(x).append(",").append(location.getBlockY()).append(",").append(z).append(".water");
|
||||
currentWater = plugin.getSprinklerManager().data.getInt(stringBuilder.toString());
|
||||
currentWater += ConfigReader.Config.sprinklerRefill;
|
||||
if (currentWater > maxWater){
|
||||
currentWater = maxWater;
|
||||
}
|
||||
plugin.getSprinklerManager().data.set(stringBuilder.toString(), currentWater);
|
||||
}
|
||||
}
|
||||
Location loc = armorStand.getLocation().add(0, ConfigReader.Message.sprinklerOffset,0);
|
||||
if (ConfigReader.Message.hasSprinklerInfo){
|
||||
String string = ConfigReader.Message.sprinklerLeft + ConfigReader.Message.sprinklerFull.repeat(currentWater) +
|
||||
ConfigReader.Message.sprinklerEmpty.repeat(maxWater - currentWater) + ConfigReader.Message.sprinklerRight;
|
||||
if(HoloUtil.cache.get(player) == null) {
|
||||
HoloUtil.showHolo(string.replace("{max_water}", String.valueOf(maxWater)).replace("{water}", String.valueOf(currentWater)), player, loc, ConfigReader.Message.sprinklerTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||
|
||||
public class ItemSpawn implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void entitySpawn(EntitySpawnEvent event){
|
||||
if(event.getEntity() instanceof Item item) {
|
||||
if(CustomStack.byItemStack(item.getItemStack()) != null){
|
||||
String id = CustomStack.byItemStack(item.getItemStack()).getId();
|
||||
// if(ConfigReader.SPRINKLERS.get(id) != null){
|
||||
// item.remove();
|
||||
// item.getWorld().dropItem(item.getLocation() ,CustomStack.getInstance(ConfigReader.SPRINKLERS.get(id).getNamespacedID_1()).getItemStack());
|
||||
// }else
|
||||
if(id.contains("_stage_")){
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.datamanager.CropManager;
|
||||
import net.momirealms.customcrops.datamanager.PotManager;
|
||||
import net.momirealms.customcrops.datamanager.SeasonManager;
|
||||
import net.momirealms.customcrops.datamanager.SprinklerManager;
|
||||
import net.momirealms.customcrops.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.fertilizer.QualityCrop;
|
||||
import net.momirealms.customcrops.fertilizer.RetainingSoil;
|
||||
import net.momirealms.customcrops.fertilizer.SpeedGrow;
|
||||
import net.momirealms.customcrops.integrations.Integration;
|
||||
import net.momirealms.customcrops.limits.CropsPerChunk;
|
||||
import net.momirealms.customcrops.limits.SprinklersPerChunk;
|
||||
import net.momirealms.customcrops.requirements.PlantingCondition;
|
||||
import net.momirealms.customcrops.requirements.Requirement;
|
||||
import net.momirealms.customcrops.utils.*;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class RightClick implements Listener {
|
||||
|
||||
private final HashMap<Player, Long> coolDown = new HashMap<>();
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event){
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
if (time - (coolDown.getOrDefault(player, time - 250)) < 250) {
|
||||
return;
|
||||
}
|
||||
coolDown.put(player, time);
|
||||
Action action = event.getAction();
|
||||
if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK){
|
||||
ItemStack itemStack = event.getItem();
|
||||
if (itemStack == null && action == Action.RIGHT_CLICK_BLOCK){
|
||||
Block block = event.getClickedBlock();
|
||||
Location location = block.getLocation();
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) return;
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if (!integration.canBreak(location, player)) return;
|
||||
}
|
||||
String namespacedID = customBlock.getNamespacedID();
|
||||
if (namespacedID.contains("_stage_")){
|
||||
if(namespacedID.equals(ConfigReader.Basic.dead)) return;
|
||||
String[] cropNameList = StringUtils.split(customBlock.getId(), "_");
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) == null) {
|
||||
if (ConfigReader.Config.quality){
|
||||
CropInstance cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
|
||||
ThreadLocalRandom current = ThreadLocalRandom.current();
|
||||
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
|
||||
World world = location.getWorld();
|
||||
Location itemLoc = location.clone().add(0.5,0.2,0.5);
|
||||
Fertilizer fertilizer = PotManager.Cache.get(location.clone().subtract(0,1,0));
|
||||
if (fertilizer != null){
|
||||
if (fertilizer instanceof QualityCrop qualityCrop){
|
||||
int[] weights = qualityCrop.getChance();
|
||||
double weightTotal = weights[0] + weights[1] + weights[2];
|
||||
double rank_1 = weights[0]/(weightTotal);
|
||||
double rank_2 = 1 - weights[1]/(weightTotal);
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < rank_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > rank_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < random; i++){
|
||||
double ran = Math.random();
|
||||
if (ran < ConfigReader.Config.quality_1){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
|
||||
}else if(ran > ConfigReader.Config.quality_2){
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
|
||||
}else {
|
||||
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
customBlock.getLoot().forEach(loot-> location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), loot));
|
||||
}
|
||||
CustomBlock.remove(location);
|
||||
CropInstance crop = ConfigReader.CROPS.get(cropNameList[0]);
|
||||
if(crop.getReturnStage() != null){
|
||||
CustomBlock.place(crop.getReturnStage(), location);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
NBTItem nbtItem = new NBTItem(itemStack);
|
||||
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
|
||||
if (nbtCompound != null){
|
||||
String id = nbtCompound.getString("id");
|
||||
if (id.endsWith("_seeds") && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
|
||||
String cropName = StringUtils.remove(id, "_seeds");
|
||||
Optional<CropInstance> crop = Optional.ofNullable(ConfigReader.CROPS.get(cropName));
|
||||
if (crop.isPresent()){
|
||||
Block block = event.getClickedBlock();
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) return;
|
||||
String namespacedID = customBlock.getNamespacedID();
|
||||
if (namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
|
||||
Location location = block.getLocation().add(0,1,0); //已+1
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if(!integration.canPlace(location, player)) return;
|
||||
}
|
||||
CropInstance cropInstance = crop.get();
|
||||
PlantingCondition plantingCondition = new PlantingCondition(player, location);
|
||||
for (Requirement requirement : cropInstance.getRequirements()){
|
||||
if (!requirement.canPlant(plantingCondition)) return;
|
||||
}
|
||||
Label_out:
|
||||
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
|
||||
for (String season : cropInstance.getSeasons()) {
|
||||
if (season.equals(SeasonManager.SEASON.get(location.getWorld().getName()))){
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
if(ConfigReader.Season.greenhouse){
|
||||
for(int i = 1; i <= ConfigReader.Season.range; i++){
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(location.clone().add(0,i,0).getBlock());
|
||||
if (cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigReader.Basic.glass)){
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.badSeason);
|
||||
return;
|
||||
}
|
||||
if(location.getBlock().getType() != Material.AIR){
|
||||
return;
|
||||
}
|
||||
if(CropsPerChunk.isLimited(location)){
|
||||
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.crop_limit.replace("{max}", String.valueOf(ConfigReader.Config.cropLimit)));
|
||||
return;
|
||||
}
|
||||
itemStack.setAmount(itemStack.getAmount() - 1);
|
||||
CropManager.Cache.put(location, cropName);
|
||||
CustomBlock.place((nbtCompound.getString("namespace") + ":" + cropName + "_stage_1"), location);
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.not_configed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Optional<WateringCan> can = Optional.ofNullable(ConfigReader.CANS.get(id));
|
||||
if (can.isPresent()){
|
||||
WateringCan wateringCan = can.get();
|
||||
int water = nbtItem.getInteger("WaterAmount");
|
||||
List<Block> lineOfSight = player.getLineOfSight(null, 5);
|
||||
for (Block block : lineOfSight) {
|
||||
if (block.getType() == Material.WATER) {
|
||||
if (wateringCan.getMax() > water){
|
||||
nbtItem.setInteger("WaterAmount", water + 1);
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ITEM_BUCKET_FILL,1,1);
|
||||
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(water != 0 && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
|
||||
Block block = event.getClickedBlock();
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) return;
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if(!integration.canPlace(block.getLocation(), player)) return;
|
||||
}
|
||||
String namespacedID = customBlock.getNamespacedID();
|
||||
if (namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
|
||||
nbtItem.setInteger("WaterAmount", water - 1);
|
||||
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
|
||||
player.getWorld().playSound(player.getLocation(), Sound.BLOCK_WATER_AMBIENT,1,1);
|
||||
waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation(), player.getLocation().getYaw());
|
||||
}else if (namespacedID.contains("_stage_")){
|
||||
nbtItem.setInteger("WaterAmount", water - 1);
|
||||
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
|
||||
player.getWorld().playSound(player.getLocation(), Sound.BLOCK_WATER_AMBIENT,1,1);
|
||||
waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation().subtract(0,1,0), player.getLocation().getYaw());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Optional<Fertilizer> fertilize = Optional.ofNullable(ConfigReader.FERTILIZERS.get(id));
|
||||
if (fertilize.isPresent() && action == Action.RIGHT_CLICK_BLOCK){
|
||||
Fertilizer fertilizerConfig = fertilize.get();
|
||||
Block block = event.getClickedBlock();
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) return;
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if(!integration.canPlace(block.getLocation(), player)) return;
|
||||
}
|
||||
String namespacedID = customBlock.getNamespacedID();
|
||||
if (namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
|
||||
itemStack.setAmount(itemStack.getAmount() - 1);
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ITEM_HOE_TILL,1,1);
|
||||
addFertilizer(fertilizerConfig, block);
|
||||
}else if (!fertilizerConfig.isBefore() && namespacedID.contains("_stage_")){
|
||||
itemStack.setAmount(itemStack.getAmount() - 1);
|
||||
addFertilizer(fertilizerConfig, block);
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ITEM_HOE_TILL,1,1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Optional<Sprinkler> sprinkler = Optional.ofNullable(ConfigReader.SPRINKLERS.get(id));
|
||||
if (sprinkler.isPresent() && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
|
||||
Location location = event.getClickedBlock().getLocation();
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if (!integration.canPlace(location, player)) return;
|
||||
}
|
||||
if(IAFurniture.getFromLocation(location.clone().add(0.5, 1.5, 0.5), location.getWorld())){
|
||||
return;
|
||||
}
|
||||
if(SprinklersPerChunk.isLimited(location)){
|
||||
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.sprinkler_limit.replace("{max}", String.valueOf(ConfigReader.Config.sprinklerLimit)));
|
||||
return;
|
||||
}
|
||||
Sprinkler sprinklerData = new Sprinkler(sprinkler.get().getRange(), 0);
|
||||
SprinklerManager.Cache.put(location.add(0,1,0), sprinklerData);
|
||||
IAFurniture.placeFurniture(sprinkler.get().getNamespacedID_2(),location);
|
||||
return;
|
||||
}
|
||||
if (ConfigReader.Message.hasCropInfo && id.equals(ConfigReader.Basic.soilDetector) && action == Action.RIGHT_CLICK_BLOCK){
|
||||
Block block = event.getClickedBlock();
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) return;
|
||||
for (Integration integration : ConfigReader.Config.integration){
|
||||
if(!integration.canPlace(block.getLocation(), player)) return;
|
||||
}
|
||||
String namespacedID = customBlock.getNamespacedID();
|
||||
if (namespacedID.contains("_stage_")){
|
||||
Location location = block.getLocation().subtract(0,1,0);
|
||||
Fertilizer fertilizer = PotManager.Cache.get(location);
|
||||
if (fertilizer != null){
|
||||
Fertilizer config = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
|
||||
String name = config.getName();
|
||||
int max_times = config.getTimes();
|
||||
if(HoloUtil.cache.get(player) == null) {
|
||||
HoloUtil.showHolo(ConfigReader.Message.cropText.replace("{fertilizer}", name).replace("{times}", String.valueOf(fertilizer.getTimes())).replace("{max_times}", String.valueOf(max_times)), player, location.add(0.5, ConfigReader.Message.cropOffset, 0.5), ConfigReader.Message.cropTime);
|
||||
}
|
||||
}
|
||||
}else if(namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
|
||||
Location location = block.getLocation();
|
||||
Fertilizer fertilizer = PotManager.Cache.get(block.getLocation());
|
||||
if (fertilizer != null){
|
||||
Fertilizer config = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
|
||||
String name = config.getName();
|
||||
int max_times = config.getTimes();
|
||||
if(HoloUtil.cache.get(player) == null){
|
||||
HoloUtil.showHolo(ConfigReader.Message.cropText.replace("{fertilizer}", name).replace("{times}", String.valueOf(fertilizer.getTimes())).replace("{max_times}", String.valueOf(max_times)), player, location.add(0.5,ConfigReader.Message.cropOffset,0.5), ConfigReader.Message.cropTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event){
|
||||
coolDown.remove(event.getPlayer());
|
||||
}
|
||||
|
||||
private void addFertilizer(Fertilizer fertilizerConfig, Block block) {
|
||||
if (fertilizerConfig instanceof QualityCrop config){
|
||||
QualityCrop qualityCrop = new QualityCrop(config.getKey(), config.getTimes(), config.getChance(), config.isBefore());
|
||||
PotManager.Cache.put(block.getLocation(), qualityCrop);
|
||||
}else if (fertilizerConfig instanceof SpeedGrow config){
|
||||
SpeedGrow speedGrow = new SpeedGrow(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
|
||||
PotManager.Cache.put(block.getLocation(), speedGrow);
|
||||
}else if (fertilizerConfig instanceof RetainingSoil config){
|
||||
RetainingSoil retainingSoil = new RetainingSoil(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
|
||||
PotManager.Cache.put(block.getLocation(), retainingSoil);
|
||||
}
|
||||
}
|
||||
|
||||
private void waterPot(int width, int length, Location clickedLocation, float yaw){
|
||||
int extend = width / 2;
|
||||
// -90~90 z+
|
||||
// -180~-90 & 90-180 z-
|
||||
// -180~0 x+
|
||||
// 0~180 x-
|
||||
if (yaw < 45 && yaw > -135) {
|
||||
// -45 ~ 45
|
||||
if (yaw > -45) {
|
||||
for (int i = -extend; i <= extend; i++) {
|
||||
Location tempLoc = clickedLocation.clone().add(i, 0, -1);
|
||||
for (int j = 0; j < length; j++){
|
||||
tempLoc.add(0,0,1);
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(customBlock != null){
|
||||
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -135 ~ -45
|
||||
else {
|
||||
for (int i = -extend; i <= extend; i++) {
|
||||
Location tempLoc = clickedLocation.clone().add(-1, 0, i);
|
||||
for (int j = 0; j < length; j++){
|
||||
tempLoc.add(1,0,0);
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(customBlock != null){
|
||||
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 45 ~ 135
|
||||
if (yaw > 45 && yaw < 135) {
|
||||
for (int i = -extend; i <= extend; i++) {
|
||||
Location tempLoc = clickedLocation.clone().add(1, 0, i);
|
||||
for (int j = 0; j < length; j++){
|
||||
tempLoc.subtract(1,0,0);
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(customBlock != null){
|
||||
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -180 ~ -135 135~180
|
||||
else {
|
||||
for (int i = -extend; i <= extend; i++) {
|
||||
Location tempLoc = clickedLocation.clone().add(i, 0, 1);
|
||||
for (int j = 0; j < length; j++){
|
||||
tempLoc.subtract(0,0,1);
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(customBlock != null){
|
||||
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.limits.MaxSprinklersPerChunk;
|
||||
import net.momirealms.customcrops.datamanager.SprinklerManager;
|
||||
import net.momirealms.customcrops.utils.IAFurniture;
|
||||
import net.momirealms.customcrops.integrations.IntegrationCheck;
|
||||
import net.momirealms.customcrops.datamanager.MessageManager;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RightClickBlock implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void rightClickBlock(PlayerInteractEvent event){
|
||||
|
||||
if(!event.hasItem()) return;
|
||||
if(event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) return;
|
||||
|
||||
CustomStack customStack = CustomStack.byItemStack(event.getItem());
|
||||
|
||||
if(customStack != null){
|
||||
Player player = event.getPlayer();
|
||||
ItemStack itemStack = event.getItem();
|
||||
String namespacedId = customStack.getNamespacedID();
|
||||
//检测手中物品是否可能为水壶
|
||||
if(itemStack.getType() == Material.WOODEN_SWORD){
|
||||
List<Block> lineOfSight = player.getLineOfSight(null, 3);
|
||||
//检测范围内是否有水
|
||||
boolean hasWater = false;
|
||||
for (final Block block : lineOfSight) {
|
||||
if (block.getType() == Material.WATER) {
|
||||
hasWater = true;
|
||||
}
|
||||
}
|
||||
if(hasWater){
|
||||
|
||||
if(namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_1) ||
|
||||
namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_2) ||
|
||||
namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_3)) {
|
||||
if(customStack.getMaxDurability() == customStack.getDurability()){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.can_full, player);
|
||||
}else {
|
||||
customStack.setDurability(customStack.getDurability() + 1);
|
||||
player.getWorld().playSound(player.getLocation(),Sound.ITEM_BUCKET_FILL,1,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getBlockFace() == BlockFace.UP) {
|
||||
|
||||
if(namespacedId.equalsIgnoreCase(ConfigManager.Config.sprinkler_1i) || namespacedId.equalsIgnoreCase(ConfigManager.Config.sprinkler_2i)){
|
||||
Location location = event.getClickedBlock().getLocation();
|
||||
//兼容性检测
|
||||
if(!IntegrationCheck.PlaceCheck(location,player)){
|
||||
return;
|
||||
}
|
||||
//高度限制
|
||||
if(event.getClickedBlock().getY() > ConfigManager.Config.maxh || event.getClickedBlock().getY() < ConfigManager.Config.minh){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.bad_place,player);
|
||||
return;
|
||||
}
|
||||
//此位置是否已有洒水器
|
||||
if(IAFurniture.getFromLocation(location.clone().add(0.5, 1.5, 0.5), location.getWorld())){
|
||||
return;
|
||||
}
|
||||
//区块上限
|
||||
if(MaxSprinklersPerChunk.maxSprinklersPerChunk(location)){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.limit_sprinkler.replace("{Max}", String.valueOf(ConfigManager.Config.max_sprinkler)),player);
|
||||
return;
|
||||
}
|
||||
if(player.getGameMode() != GameMode.CREATIVE){
|
||||
itemStack.setAmount(itemStack.getAmount() -1);
|
||||
}
|
||||
if(namespacedId.equalsIgnoreCase(ConfigManager.Config.sprinkler_1i)){
|
||||
SprinklerManager.putInstance(location.clone().add(0,1,0),"s1");
|
||||
}else {
|
||||
SprinklerManager.putInstance(location.clone().add(0,1,0),"s2");
|
||||
}
|
||||
IAFurniture.placeFurniture(namespacedId.replace("_item",""),location.clone().add(0,1,0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
package net.momirealms.customcrops.listener;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import dev.lone.itemsadder.api.Events.CustomBlockInteractEvent;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.limits.MaxCropsPerChunk;
|
||||
import net.momirealms.customcrops.integrations.IntegrationCheck;
|
||||
import net.momirealms.customcrops.datamanager.MessageManager;
|
||||
import net.momirealms.customcrops.utils.Crop;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.momirealms.customcrops.datamanager.CropManager.CROPS;
|
||||
|
||||
public class RightClickCustomBlock implements Listener {
|
||||
|
||||
private HashMap<Player, Long> coolDown;
|
||||
{
|
||||
coolDown = new HashMap<Player, Long>();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void rightClickCustomBlock(CustomBlockInteractEvent event){
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
||||
|
||||
Block clickedBlock = event.getBlockClicked();
|
||||
Location clickedBlockLocation = clickedBlock.getLocation();
|
||||
/*
|
||||
手里无物品,则进行收获判断
|
||||
手里有物品,则进行浇水,骨粉,种植判断
|
||||
*/
|
||||
//空手部分
|
||||
if (event.getItem() == null) {
|
||||
CustomBlock clickedCustomBlock = CustomBlock.byAlreadyPlaced(clickedBlock);
|
||||
Player player = event.getPlayer();
|
||||
//兼容性检测
|
||||
if(IntegrationCheck.HarvestCheck(clickedBlockLocation, player)){
|
||||
//获取点击方块的命名空间与ID
|
||||
String namespacedID = event.getNamespacedID();
|
||||
//如果ID内有stage则进行下一步
|
||||
if (namespacedID.contains("_stage_")){
|
||||
//是否为枯萎植物
|
||||
if(namespacedID.equalsIgnoreCase(ConfigManager.Config.dead)) return;
|
||||
String[] split = StringUtils.split(namespacedID,":");
|
||||
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
//农作物是否存在下一阶段
|
||||
if (CustomBlock.getInstance(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage) == null) {
|
||||
//如果不存在下一阶段说明已是最终阶段,可以收获
|
||||
//遍历掉落物并删除方块
|
||||
clickedCustomBlock.getLoot().forEach(itemStack -> clickedBlockLocation.getWorld().dropItem(clickedBlockLocation.clone().add(0.5,0.2,0.5),itemStack));
|
||||
CustomBlock.remove(clickedBlockLocation);
|
||||
//如果配置文件中有return项目则放置方块
|
||||
Crop crop = ConfigManager.CONFIG.get(cropNameList[0]);
|
||||
if(crop.getWillReturn()){
|
||||
CustomBlock.place(crop.getReturnStage(), clickedBlockLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//获取右键物品的namespaceID
|
||||
String namespacedId = event.getNamespacedID();
|
||||
/*
|
||||
右键的是特殊作物吗
|
||||
*/
|
||||
if (namespacedId.contains("stage")) {
|
||||
//下方方块不是自定义方块则返回
|
||||
Player player = event.getPlayer();
|
||||
Block blockUnder = clickedBlockLocation.clone().subtract(0,1,0).getBlock();
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(blockUnder);
|
||||
if (cb == null) return;
|
||||
//检测右键的方块下方是否为干燥的种植盆方块
|
||||
if (cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot)) {
|
||||
//获取手中的物品
|
||||
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
||||
Location locUnder = clickedBlockLocation.clone().subtract(0,1,0);
|
||||
//如果手中的是水桶,那么转干为湿
|
||||
if (mainHandItem.getType() == Material.WATER_BUCKET) {
|
||||
//扣除水桶
|
||||
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
||||
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
||||
}
|
||||
CustomBlock.remove(locUnder);
|
||||
CustomBlock.place(ConfigManager.Config.watered_pot, locUnder);
|
||||
} else if (mainHandItem.getType() == Material.WOODEN_SWORD) {
|
||||
waterPot(mainHandItem, player, locUnder);
|
||||
}
|
||||
}
|
||||
//检测右键的方块下方是否为湿润的种植盆方块
|
||||
else if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.watered_pot)){
|
||||
//获取手中的物品
|
||||
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
||||
//如果是骨粉
|
||||
if (mainHandItem.getType() == Material.BONE_MEAL){
|
||||
//植物是否具有stage属性
|
||||
if (namespacedId.contains("_stage_")){
|
||||
String[] split = StringUtils.split(namespacedId,":");
|
||||
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||
//下一生长阶段
|
||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||
//植物是否存在下一个stage
|
||||
if (CustomBlock.getInstance(split[0]+ ":" + cropNameList[0] + "_stage_" + nextStage) != null){
|
||||
if(player.getGameMode() != GameMode.CREATIVE){
|
||||
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
||||
}
|
||||
World world = player.getWorld();
|
||||
//骨粉的成功率
|
||||
if (Math.random() < ConfigManager.Config.bone_chance){
|
||||
CustomBlock.remove(clickedBlockLocation);
|
||||
CustomBlock.place(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage,clickedBlockLocation);
|
||||
Particle particleSuccess = Particle.valueOf(ConfigManager.Config.success);
|
||||
world.spawnParticle(particleSuccess, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
||||
//使用骨粉是否消耗水分
|
||||
if(ConfigManager.Config.need_water){
|
||||
CustomBlock.remove(clickedBlockLocation.clone().subtract(0,1,0));
|
||||
CustomBlock.place(ConfigManager.Config.pot, clickedBlockLocation.clone().subtract(0,1,0));
|
||||
}
|
||||
}else {
|
||||
Particle particleFailure = Particle.valueOf(ConfigManager.Config.failure);
|
||||
world.spawnParticle(particleFailure, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
右键的是种植盆吗
|
||||
*/
|
||||
else if (event.getBlockFace() == BlockFace.UP){
|
||||
//获取手中的物品
|
||||
ItemStack item = event.getItem();
|
||||
Player player = event.getPlayer();
|
||||
//检测右键的方块是否为干燥的种植盆方块
|
||||
if (namespacedId.equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
//如果手中的是水桶,那么转干为湿
|
||||
if (item.getType() == Material.WATER_BUCKET){
|
||||
//扣除水桶
|
||||
if(player.getGameMode() != GameMode.CREATIVE){
|
||||
item.setAmount(item.getAmount() - 1);
|
||||
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
||||
}
|
||||
CustomBlock.remove(clickedBlockLocation);
|
||||
CustomBlock.place(ConfigManager.Config.watered_pot,clickedBlockLocation);
|
||||
return;
|
||||
}
|
||||
CustomStack customStack = CustomStack.byItemStack(item);
|
||||
if (customStack != null){
|
||||
String namespacedID = customStack.getNamespacedID();
|
||||
if (namespacedID.endsWith("_seeds")){
|
||||
if(tryPlantSeed(clickedBlockLocation, namespacedID, player)){
|
||||
if(player.getGameMode() != GameMode.CREATIVE){
|
||||
item.setAmount(item.getAmount() -1);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
waterPot(item, player, clickedBlockLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
//检测右键的方块是否为湿润的种植盆方块
|
||||
else if(namespacedId.equalsIgnoreCase(ConfigManager.Config.watered_pot)){
|
||||
CustomStack customStack = CustomStack.byItemStack(item);
|
||||
if (customStack != null){
|
||||
String namespacedID = customStack.getNamespacedID();
|
||||
if (namespacedID.endsWith("_seeds")){
|
||||
if(tryPlantSeed(clickedBlockLocation, namespacedID, player)){
|
||||
if(player.getGameMode() != GameMode.CREATIVE){
|
||||
item.setAmount(item.getAmount() -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//尝试种植植物
|
||||
private boolean tryPlantSeed(Location clickedBlockLocation, String namespacedID, Player player) {
|
||||
//获取农作物名
|
||||
String key = StringUtils.split(namespacedID.replace("_seeds",""),":")[1];
|
||||
//检测上方为空气
|
||||
if(clickedBlockLocation.clone().add(0, 1, 0).getBlock().getType() != Material.AIR){
|
||||
return false;
|
||||
}
|
||||
//该种子是否存在于配置文件中
|
||||
if(!ConfigManager.CONFIG.containsKey(key)){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.no_such_seed,player);
|
||||
return false;
|
||||
}
|
||||
//是否超高超低
|
||||
if (clickedBlockLocation.getY() < ConfigManager.Config.minh || clickedBlockLocation.getY() > ConfigManager.Config.maxh){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.bad_place,player);
|
||||
return false;
|
||||
}
|
||||
|
||||
Location locUp = clickedBlockLocation.clone().add(0,1,0);
|
||||
//兼容性检测
|
||||
if(!IntegrationCheck.PlaceCheck(locUp,player)){
|
||||
return false;
|
||||
}
|
||||
//是否启用了季节
|
||||
Label_out:
|
||||
if(ConfigManager.Config.season){
|
||||
if(ConfigManager.Config.greenhouse){
|
||||
int range = ConfigManager.Config.range;
|
||||
for(int i = 1; i <= range; i++){
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(locUp.clone().add(0,i,0).getBlock());
|
||||
if (cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.glass)){
|
||||
break Label_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//获取种子适宜生长的季节
|
||||
boolean ws = true;
|
||||
Crop crop = ConfigManager.CONFIG.get(key);
|
||||
for(String season : crop.getSeasons()){
|
||||
if (Objects.equals(season, ConfigManager.Config.current)) {
|
||||
ws = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ws){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.wrong_season,player);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//是否到达区块上限
|
||||
if(MaxCropsPerChunk.maxCropsPerChunk(clickedBlockLocation)){
|
||||
MessageManager.playerMessage(ConfigManager.Config.prefix + ConfigManager.Config.limit_crop.replace("{Max}", String.valueOf(ConfigManager.Config.max_crop)),player);
|
||||
return false;
|
||||
}
|
||||
//添加到缓存中
|
||||
CROPS.put(locUp, key);
|
||||
//放置自定义农作物
|
||||
CustomBlock.place(namespacedID.replace("_seeds","_stage_1"),locUp);
|
||||
return true;
|
||||
}
|
||||
private void waterPot(ItemStack itemStack, Player player, Location location){
|
||||
//是否为IA物品
|
||||
if(CustomStack.byItemStack(itemStack) == null) return;
|
||||
//获取IA物品
|
||||
CustomStack customStack = CustomStack.byItemStack(itemStack);
|
||||
String namespacedId = customStack.getNamespacedID();
|
||||
World world = player.getWorld();
|
||||
int x;
|
||||
int z;
|
||||
if (namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_1)) {
|
||||
x = 0;
|
||||
z = 0;
|
||||
} else if (namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_2)){
|
||||
x = 2;
|
||||
z = 2;
|
||||
} else if (namespacedId.equalsIgnoreCase(ConfigManager.Config.watering_can_3)){
|
||||
x = 4;
|
||||
z = 4;
|
||||
} else return;
|
||||
//判断耐久度
|
||||
if(customStack.getDurability() > 0){
|
||||
CustomStack.byItemStack(itemStack).setDurability(CustomStack.byItemStack(itemStack).getDurability() - 1);
|
||||
}else return;
|
||||
//兼容性检测
|
||||
if(!IntegrationCheck.PlaceCheck(location,player)){
|
||||
return;
|
||||
}
|
||||
//播放洒水音效
|
||||
world.playSound(player.getLocation(),Sound.BLOCK_WATER_AMBIENT,1,1);
|
||||
//获取玩家朝向
|
||||
float yaw = player.getLocation().getYaw();
|
||||
//根据朝向确定浇水方向
|
||||
if (yaw <= 45 && yaw >= -135) {
|
||||
if (yaw > -45) {
|
||||
x = 0;
|
||||
} else {
|
||||
z = 0;
|
||||
}
|
||||
for (int i = 0; i <= x; i++) {
|
||||
for (int j = 0; j <= z; j++) {
|
||||
Location tempLoc = location.clone().add(i, 0, j);
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigManager.Config.watered_pot,tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (yaw < 135 && yaw > 45) {
|
||||
z= 0;
|
||||
} else {
|
||||
x= 0;
|
||||
}
|
||||
for (int i = 0; i <= x; i++) {
|
||||
for (int j = 0; j <= z; j++) {
|
||||
Location tempLoc = location.clone().subtract(i, 0, j);
|
||||
CustomBlock cb = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
|
||||
if(cb != null){
|
||||
if(cb.getNamespacedID().equalsIgnoreCase(ConfigManager.Config.pot)){
|
||||
CustomBlock.remove(tempLoc);
|
||||
CustomBlock.place(ConfigManager.Config.watered_pot,tempLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record Biome(List<String> biomes) implements Requirement {
|
||||
|
||||
public List<String> getBiomes() {
|
||||
return this.biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlant(PlantingCondition plantingCondition) {
|
||||
String currentBiome = plantingCondition.getLocation().getBlock().getBiome().getKey().toString();
|
||||
for (String biome : biomes) {
|
||||
if (currentBiome.equalsIgnoreCase(biome)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
AdventureManager.playerMessage(plantingCondition.player(), ConfigReader.Message.prefix +ConfigReader.Message.badBiome);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
|
||||
public record Permission(String permission) implements Requirement {
|
||||
|
||||
public String getPermission() {
|
||||
return this.permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlant(PlantingCondition plantingCondition) {
|
||||
if (plantingCondition.getPlayer().hasPermission(permission)){
|
||||
return true;
|
||||
}
|
||||
AdventureManager.playerMessage(plantingCondition.player(), ConfigReader.Message.prefix +ConfigReader.Message.badPerm);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public record PlantingCondition (Player player, Location location){
|
||||
public Location getLocation() { return location; }
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
public interface Requirement {
|
||||
boolean canPlant(PlantingCondition plantingCondition);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record World(List<String> worlds) implements Requirement {
|
||||
|
||||
public List<String> getWorlds() {
|
||||
return this.worlds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlant(PlantingCondition plantingCondition) {
|
||||
org.bukkit.World world = plantingCondition.getLocation().getWorld();
|
||||
if (worlds.contains(world.getName())){
|
||||
return true;
|
||||
}
|
||||
AdventureManager.playerMessage(plantingCondition.player(), ConfigReader.Message.prefix +ConfigReader.Message.badWorld);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.momirealms.customcrops.requirements;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.utils.AdventureManager;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record YPos(List<String> yPos) implements Requirement {
|
||||
|
||||
public List<String> getYPos() {
|
||||
return this.yPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlant(PlantingCondition plantingCondition) {
|
||||
int y = (int) plantingCondition.getLocation().getY();
|
||||
for (String range : yPos) {
|
||||
String[] yMinMax = StringUtils.split(range, "~");
|
||||
if (y > Integer.parseInt(yMinMax[0]) && y < Integer.parseInt(yMinMax[1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
AdventureManager.playerMessage(plantingCondition.player(), ConfigReader.Message.prefix +ConfigReader.Message.badY);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,19 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class CropTimer {
|
||||
|
||||
int taskID;
|
||||
private final int taskID;
|
||||
|
||||
public static void stopTimer(int ID) {
|
||||
Bukkit.getScheduler().cancelTask(ID);
|
||||
Bukkit.getServer().getScheduler().cancelTask(ID);
|
||||
}
|
||||
|
||||
public CropTimer() {
|
||||
TimeCheck tc = new TimeCheck();
|
||||
public CropTimer(CustomCrops plugin) {
|
||||
TimeCheck tc = new TimeCheck(plugin);
|
||||
BukkitTask task = tc.runTaskTimer(CustomCrops.instance, 1,1);
|
||||
this.taskID = task.getTaskId();
|
||||
}
|
||||
|
||||
public void stopTimer(int ID) {
|
||||
Bukkit.getScheduler().cancelTask(ID);
|
||||
Bukkit.getServer().getScheduler().cancelTask(ID);
|
||||
}
|
||||
|
||||
public int getTaskID() {
|
||||
return this.taskID;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.momirealms.customcrops.timer;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class CropTimerAsync {
|
||||
|
||||
private final int taskID;
|
||||
|
||||
public CropTimerAsync(CustomCrops plugin) {
|
||||
TimeCheck tc = new TimeCheck(plugin);
|
||||
BukkitTask task = tc.runTaskTimerAsynchronously(CustomCrops.instance, 1,1);
|
||||
this.taskID = task.getTaskId();
|
||||
}
|
||||
|
||||
public void stopTimer(int ID) {
|
||||
Bukkit.getScheduler().cancelTask(ID);
|
||||
Bukkit.getServer().getScheduler().cancelTask(ID);
|
||||
}
|
||||
|
||||
public int getTaskID() {
|
||||
return this.taskID;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,34 @@
|
||||
package net.momirealms.customcrops.timer;
|
||||
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.datamanager.CropManager;
|
||||
import net.momirealms.customcrops.datamanager.MessageManager;
|
||||
import net.momirealms.customcrops.datamanager.SprinklerManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
public class TimeCheck extends BukkitRunnable {
|
||||
|
||||
private final CustomCrops plugin;
|
||||
public TimeCheck(CustomCrops plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ConfigManager.Config.worlds.forEach(world ->{
|
||||
if(Bukkit.getWorld(world) != null){
|
||||
long time = Bukkit.getWorld(world).getTime();
|
||||
ConfigManager.Config.cropGrowTimeList.forEach(cropGrowTime -> {
|
||||
if(time == cropGrowTime){
|
||||
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance, () -> CropManager.CropGrow(world));
|
||||
ConfigReader.Config.worlds.forEach(world ->{
|
||||
long time = world.getTime();
|
||||
ConfigReader.Config.cropGrowTimeList.forEach(cropGrowTime -> {
|
||||
if(time == 0){
|
||||
if(ConfigReader.Season.enable && ConfigReader.Season.seasonChange){
|
||||
plugin.getSeasonManager().getSeason(world);
|
||||
}
|
||||
});
|
||||
ConfigManager.Config.sprinklerWorkTimeList.forEach(sprinklerTime -> {
|
||||
if(time == sprinklerTime){
|
||||
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance, () -> SprinklerManager.SprinklerWork(world));
|
||||
}
|
||||
});
|
||||
}else {
|
||||
MessageManager.consoleMessage("&c[CustomCrops] 错误! 白名单世界 "+ world +" 不存在!",Bukkit.getConsoleSender());
|
||||
}
|
||||
}
|
||||
if(time == cropGrowTime){
|
||||
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance, () -> {
|
||||
plugin.getCropManager().cropGrow(world.getName());
|
||||
plugin.getSprinklerManager().sprinklerWork(world.getName());
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class AdventureManager {
|
||||
|
||||
public static void consoleMessage(String s) {
|
||||
Audience au = CustomCrops.adventure.sender(Bukkit.getConsoleSender());
|
||||
MiniMessage mm = MiniMessage.miniMessage();
|
||||
Component parsed = mm.deserialize(s);
|
||||
au.sendMessage(parsed);
|
||||
}
|
||||
|
||||
public static void playerMessage(Player player, String s) {
|
||||
Audience au = CustomCrops.adventure.player(player);
|
||||
MiniMessage mm = MiniMessage.miniMessage();
|
||||
Component parsed = mm.deserialize(s);
|
||||
au.sendMessage(parsed);
|
||||
}
|
||||
|
||||
public static void playerTitle(Player player, String s1, String s2, int in, int duration, int out) {
|
||||
Audience au = CustomCrops.adventure.player(player);
|
||||
MiniMessage mm = MiniMessage.miniMessage();
|
||||
Title.Times times = Title.Times.times(Duration.ofMillis(in), Duration.ofMillis(duration), Duration.ofMillis(out));
|
||||
Title title = Title.title(mm.deserialize(s1), mm.deserialize(s2), times);
|
||||
au.showTitle(title);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.customcrops.datamanager;
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
|
||||
import java.io.File;
|
||||
@@ -7,32 +8,29 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class BackUp {
|
||||
|
||||
public static void backUpData(){
|
||||
|
||||
List<String> files = Arrays.asList("crop","sprinkler","pot","season");
|
||||
|
||||
Date date = new Date();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
File crop_data = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||
File cropBackUp = new File(CustomCrops.instance.getDataFolder(), "backups"+ File.separatorChar + format.format(date) + File.separatorChar + "crop-data.yml");
|
||||
File sprinkler_data = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||
File sprinklerBackUp = new File(CustomCrops.instance.getDataFolder(), "backups"+ File.separatorChar + format.format(date) + File.separatorChar + "sprinkler-data.yml");
|
||||
|
||||
try {
|
||||
BackUp.backUp(crop_data,cropBackUp);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("crop-data.yml备份出错!");
|
||||
}
|
||||
try {
|
||||
BackUp.backUp(sprinkler_data,sprinklerBackUp);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning("sprinkler-data.yml备份出错!");
|
||||
}
|
||||
files.forEach(fileName -> {
|
||||
File data = new File(CustomCrops.instance.getDataFolder(), "data"+ File.separatorChar + fileName + ".yml");
|
||||
File backUp = new File(CustomCrops.instance.getDataFolder(), "backups"+ File.separatorChar + format.format(date) + File.separatorChar + fileName + ".yml");
|
||||
try {
|
||||
BackUp.backUp(data, backUp);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
CustomCrops.instance.getLogger().warning(fileName + ".yml备份出错!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void backUp(File file_from, File file_to) throws IOException {
|
||||
@@ -1,45 +0,0 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
public class Crop {
|
||||
|
||||
private final String key;
|
||||
private final double chance;
|
||||
private double giantChance;
|
||||
private String[] seasons;
|
||||
private boolean willReturn;
|
||||
private String returnStage;
|
||||
private boolean willGiant;
|
||||
private String giant;
|
||||
|
||||
public Crop(String key, double chance){
|
||||
this.key = key;
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public String getReturnStage(){
|
||||
return this.returnStage;
|
||||
}
|
||||
public String getGiant(){
|
||||
return this.giant;
|
||||
}
|
||||
public boolean getWillReturn(){
|
||||
return this.willReturn;
|
||||
}
|
||||
public boolean getWillGiant(){
|
||||
return this.willGiant;
|
||||
}
|
||||
public String[] getSeasons() {return this.seasons;}
|
||||
public double getChance() {return this.chance;}
|
||||
public double getGiantChance() { return this.giantChance; }
|
||||
|
||||
public void setWillReturn(boolean b){
|
||||
this.willReturn = b;
|
||||
}
|
||||
public void setReturnStage(String stage){
|
||||
this.returnStage = stage;
|
||||
}
|
||||
public void setSeasons(String[] seasons) { this.seasons = seasons; }
|
||||
public void setWillGiant(boolean b) { this.willGiant = b; }
|
||||
public void setGiant(String giant) {this.giant = giant; }
|
||||
public void setGiantChance(double giantChance) { this.giantChance = giantChance; }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import net.momirealms.customcrops.requirements.Requirement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CropInstance {
|
||||
|
||||
private double giantChance;
|
||||
private String giant;
|
||||
private List<Requirement> requirements;
|
||||
private List<String> seasons;
|
||||
private String returnStage;
|
||||
private final int min;
|
||||
private final int max;
|
||||
private String quality_1;
|
||||
private String quality_2;
|
||||
private String quality_3;
|
||||
|
||||
public CropInstance(int min, int max){
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public String getReturnStage(){
|
||||
return this.returnStage;
|
||||
}
|
||||
public String getGiant(){
|
||||
return this.giant;
|
||||
}
|
||||
public double getGiantChance() { return this.giantChance; }
|
||||
public List<Requirement> getRequirements() {return requirements;}
|
||||
public List<String> getSeasons() {return seasons;}
|
||||
|
||||
public String getQuality_1() {
|
||||
return quality_1;
|
||||
}
|
||||
|
||||
public String getQuality_2() {
|
||||
return quality_2;
|
||||
}
|
||||
|
||||
public String getQuality_3() {
|
||||
return quality_3;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
public int getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setReturnStage(String stage){
|
||||
this.returnStage = stage;
|
||||
}
|
||||
public void setGiant(String giant) {this.giant = giant; }
|
||||
public void setGiantChance(double giantChance) { this.giantChance = giantChance; }
|
||||
public void setRequirements(List<Requirement> requirements) { this.requirements = requirements; }
|
||||
public void setSeasons(List<String> seasons) { this.seasons = seasons; }
|
||||
|
||||
public void setQuality_1(String quality_1) {
|
||||
this.quality_1 = quality_1;
|
||||
}
|
||||
|
||||
public void setQuality_2(String quality_2) {
|
||||
this.quality_2 = quality_2;
|
||||
}
|
||||
|
||||
public void setQuality_3(String quality_3) {
|
||||
this.quality_3 = quality_3;
|
||||
}
|
||||
}
|
||||
63
src/main/java/net/momirealms/customcrops/utils/HoloUtil.java
Normal file
63
src/main/java/net/momirealms/customcrops/utils/HoloUtil.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
public class HoloUtil {
|
||||
|
||||
public static HashMap<Player, Entity> cache = new HashMap<>();
|
||||
|
||||
public static void showHolo(String text, Player player, Location location, int duration){
|
||||
|
||||
ArmorStand entity = location.getWorld().spawn(location, ArmorStand.class, a -> {
|
||||
a.setInvisible(true);
|
||||
a.setCollidable(false);
|
||||
a.setInvulnerable(true);
|
||||
a.setVisible(false);
|
||||
a.setCustomNameVisible(false);
|
||||
a.setSmall(true);
|
||||
a.setGravity(false);
|
||||
});
|
||||
cache.put(player, entity);
|
||||
|
||||
Component component = MiniMessage.miniMessage().deserialize(text);
|
||||
|
||||
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
|
||||
wrappedDataWatcher.setEntity(entity);
|
||||
WrappedDataWatcher.Serializer serializer = WrappedDataWatcher.Registry.get(Boolean.class);
|
||||
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(2, WrappedDataWatcher.Registry.getChatComponentSerializer(true)), Optional.of(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)).getHandle()));
|
||||
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer), true);
|
||||
PacketContainer packetContainer = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
|
||||
packetContainer.getIntegers().write(0, entity.getEntityId());
|
||||
packetContainer.getWatchableCollectionModifier().write(0, wrappedDataWatcher.getWatchableObjects());
|
||||
|
||||
try {
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packetContainer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
AdventureManager.consoleMessage("<red>[CustomCrops] 无法为玩家 "+ player.getName()+" 展示悬浮信息!</red>");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(CustomCrops.instance, ()->{
|
||||
entity.remove();
|
||||
cache.remove(player);
|
||||
}, duration * 20L);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomFurniture;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
@@ -11,15 +11,15 @@ public class IAFurniture {
|
||||
|
||||
//放置IA自定义家具
|
||||
public static void placeFurniture(String name, Location location){
|
||||
CustomFurniture.spawn(name,location.getWorld().getBlockAt(location));
|
||||
CustomFurniture.spawn(name, location.getBlock());
|
||||
}
|
||||
|
||||
//根据位置获取盔甲架,如果是洒水器返回true,否则返回false
|
||||
public static boolean getFromLocation(Location location, World world){
|
||||
for(Entity entity : world.getNearbyEntities(location,0,0,0)){
|
||||
if(entity instanceof ArmorStand){
|
||||
if(CustomFurniture.byAlreadySpawned(entity) != null){
|
||||
if(CustomFurniture.byAlreadySpawned(entity).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.sprinkler_1) || CustomFurniture.byAlreadySpawned(entity).getNamespacedID().equalsIgnoreCase(ConfigManager.Config.sprinkler_2)){
|
||||
if(entity instanceof ArmorStand armorStand){
|
||||
if(CustomFurniture.byAlreadySpawned(armorStand) != null){
|
||||
if(ConfigReader.SPRINKLERS.get(CustomFurniture.byAlreadySpawned(armorStand).getId()) != null){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
74
src/main/java/net/momirealms/customcrops/utils/NBTUtil.java
Normal file
74
src/main/java/net/momirealms/customcrops/utils/NBTUtil.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NBTUtil {
|
||||
|
||||
private final Map<?,?> nbt;
|
||||
private final NBTItem nbtItem;
|
||||
|
||||
public NBTUtil(Map<?,?> nbt, ItemStack itemStack){
|
||||
this.nbt = nbt;
|
||||
this.nbtItem = new NBTItem(itemStack);
|
||||
}
|
||||
|
||||
public NBTItem getNBTItem(){
|
||||
nbt.keySet().forEach(key -> {
|
||||
if (nbt.get(key) instanceof Map<?,?> map){
|
||||
nbtItem.addCompound((String) key);
|
||||
setTags(map, nbtItem.getCompound((String) key));
|
||||
}else {
|
||||
setNbt(nbtItem, (String) key, nbt.get(key));
|
||||
}
|
||||
});
|
||||
return this.nbtItem;
|
||||
}
|
||||
|
||||
private void setTags(Map<?,?> map, NBTCompound nbtCompound){
|
||||
map.keySet().forEach(key -> {
|
||||
if (map.get(key) instanceof Map map2){
|
||||
nbtCompound.addCompound((String) key);
|
||||
setTags(map2, nbtCompound.getCompound((String) key));
|
||||
}else {
|
||||
setNbt(nbtCompound, (String) key, map.get(key));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setNbt(NBTCompound nbtCompound, String key, Object value){
|
||||
if (value instanceof String string){
|
||||
if (string.startsWith("(Int) ")){
|
||||
nbtCompound.setInteger(key, Integer.valueOf(string.substring(6)));
|
||||
}else if (string.startsWith("(String) ")){
|
||||
nbtCompound.setString(key, string.substring(9));
|
||||
}else if (string.startsWith("(Long) ")){
|
||||
nbtCompound.setLong(key, Long.valueOf(string.substring(7)));
|
||||
}else if (string.startsWith("(Float) ")){
|
||||
nbtCompound.setFloat(key, Float.valueOf(string.substring(8)));
|
||||
} else if (string.startsWith("(Double) ")){
|
||||
nbtCompound.setDouble(key, Double.valueOf(string.substring(9)));
|
||||
}else if (string.startsWith("(Short) ")){
|
||||
nbtCompound.setShort(key, Short.valueOf(string.substring(8)));
|
||||
}else if (string.startsWith("(Boolean) ")){
|
||||
nbtCompound.setBoolean(key, Boolean.valueOf(string.substring(10)));
|
||||
}else if (string.startsWith("(UUID) ")){
|
||||
nbtCompound.setUUID(key, UUID.fromString(string.substring(7)));
|
||||
}else if (string.startsWith("(Byte) ")){
|
||||
nbtCompound.setByte(key, Byte.valueOf(string.substring(7)));
|
||||
}else {
|
||||
nbtCompound.setString(key, string);
|
||||
}
|
||||
}else {
|
||||
try {
|
||||
nbtCompound.setInteger(key, (Integer) value);
|
||||
}catch (ClassCastException e){
|
||||
e.printStackTrace();
|
||||
AdventureManager.consoleMessage("<red>[CustomFishing] 非Int类型数字必须加上强制转换标识!</red>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import net.momirealms.customcrops.datamanager.ConfigManager;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.ConfigReader;
|
||||
import net.momirealms.customcrops.datamanager.SeasonManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Placeholders extends PlaceholderExpansion{
|
||||
|
||||
public Placeholders(CustomCrops customCrops) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "customcrops";
|
||||
@@ -23,18 +21,30 @@ public class Placeholders extends PlaceholderExpansion{
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return "1.0";
|
||||
return "1.2";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onRequest(OfflinePlayer player, String params) {
|
||||
|
||||
if(params.equalsIgnoreCase("season")){
|
||||
return ConfigManager.Config.current
|
||||
.replace("spring", ConfigManager.Config.spring)
|
||||
.replace("summer", ConfigManager.Config.summer)
|
||||
.replace("autumn", ConfigManager.Config.autumn)
|
||||
.replace("winter", ConfigManager.Config.winter);
|
||||
if (params.equalsIgnoreCase("season")){
|
||||
return SeasonManager.SEASON.get(player.getPlayer().getWorld().getName())
|
||||
.replace("spring", ConfigReader.Message.spring)
|
||||
.replace("summer", ConfigReader.Message.summer)
|
||||
.replace("autumn", ConfigReader.Message.autumn)
|
||||
.replace("winter", ConfigReader.Message.winter);
|
||||
}
|
||||
if (params.startsWith("season_")){
|
||||
return SeasonManager.SEASON.get(params.substring(7))
|
||||
.replace("spring", ConfigReader.Message.spring)
|
||||
.replace("summer", ConfigReader.Message.summer)
|
||||
.replace("autumn", ConfigReader.Message.autumn)
|
||||
.replace("winter", ConfigReader.Message.winter);
|
||||
}
|
||||
if (params.equalsIgnoreCase("nextseason")){
|
||||
return String.valueOf(ConfigReader.Season.duration - ((int) ((player.getPlayer().getWorld().getFullTime() / 24000L) % (ConfigReader.Season.duration * 4)) % ConfigReader.Season.duration));
|
||||
}
|
||||
if (params.startsWith("nextseason_")){
|
||||
return String.valueOf(ConfigReader.Season.duration - ((int) ((Bukkit.getWorld(params.substring(11)).getFullTime() / 24000L) % (ConfigReader.Season.duration * 4)) % ConfigReader.Season.duration));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
public class Sprinkler {
|
||||
|
||||
private int water;
|
||||
private int range;
|
||||
//2D
|
||||
private String namespacedID_1;
|
||||
//3D
|
||||
private String namespacedID_2;
|
||||
|
||||
public Sprinkler(int range, int water){
|
||||
this.water = water;
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
public int getWater() {
|
||||
return water;
|
||||
}
|
||||
|
||||
public String getNamespacedID_1() {
|
||||
return namespacedID_1;
|
||||
}
|
||||
|
||||
public String getNamespacedID_2() {
|
||||
return namespacedID_2;
|
||||
}
|
||||
|
||||
public int getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
public void setRange(int range) {
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
public void setNamespacedID_2(String namespacedID_2) {
|
||||
this.namespacedID_2 = namespacedID_2;
|
||||
}
|
||||
|
||||
public void setNamespacedID_1(String namespacedID_1) {
|
||||
this.namespacedID_1 = namespacedID_1;
|
||||
}
|
||||
|
||||
public void setWater(int water) {
|
||||
this.water = water;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.momirealms.customcrops.utils;
|
||||
|
||||
public class WateringCan {
|
||||
|
||||
private final int max;
|
||||
private final int width;
|
||||
private final int length;
|
||||
|
||||
public WateringCan(int max, int width, int length){
|
||||
this.length = length;
|
||||
this.max = max;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
}
|
||||
50
src/main/resources/basic.yml
Normal file
50
src/main/resources/basic.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
#填写IA物品的命名空间与物品ID
|
||||
basic:
|
||||
#植物的种植盆方块
|
||||
pot: customcrops:pot
|
||||
#植物的浇过水的种植盆方块
|
||||
watered-pot: customcrops:watered_pot
|
||||
#温室玻璃方块
|
||||
greenhouse-glass: customcrops:greenhouse_glass
|
||||
#农作物枯萎后变成的方块,物品ID中请保留stage以保持其下方方块被破坏时,枯萎作物也被破坏的特性
|
||||
dead-crop: customcrops:crop_stage_death
|
||||
#土质探测器,用于查看使用的肥料种类和残余量
|
||||
soil-detector: customcrops:soil_detector
|
||||
|
||||
water-can:
|
||||
watering_can_1:
|
||||
item: customcrops:watering_can_1
|
||||
#水壶最大容量
|
||||
max: 3
|
||||
#水壶工作的范围
|
||||
width: 1
|
||||
length: 1
|
||||
watering_can_2:
|
||||
item: customcrops:watering_can_2
|
||||
max: 4
|
||||
width: 1
|
||||
length: 3
|
||||
watering_can_3:
|
||||
item: customcrops:watering_can_3
|
||||
max: 5
|
||||
width: 3
|
||||
length: 3
|
||||
watering_can_4:
|
||||
item: customcrops:watering_can_4
|
||||
max: 6
|
||||
width: 3
|
||||
length: 5
|
||||
|
||||
sprinkler:
|
||||
sprinkler_1:
|
||||
#洒水器工作范围
|
||||
range: 1
|
||||
#洒水器最大水储量
|
||||
max-water: 5
|
||||
3Ditem: customcrops:sprinkler_1
|
||||
2Ditem: customcrops:sprinkler_1_item
|
||||
sprinkler_2:
|
||||
range: 2
|
||||
max-water: 7
|
||||
3Ditem: customcrops:sprinkler_2
|
||||
2Ditem: customcrops:sprinkler_2_item
|
||||
@@ -1,114 +1,55 @@
|
||||
#是否使用季节
|
||||
#非植物季节则无法耕种,过了季节则枯死
|
||||
enable-season: false
|
||||
#当前季节
|
||||
#使用/customcrops setseason 来切换季节
|
||||
#使用/customcrops nextseason 进入下一季节
|
||||
current-season: spring
|
||||
|
||||
config:
|
||||
#植物生长的可能时间点,你可以在一天设置多个时间点判断生长
|
||||
#为了防止植物生长过快你可以适当调低生长一个阶段的概率
|
||||
#请尽量在植物生长后200ticks以上设置洒水器工作点,如果生长和洒水时间靠太近可能会带来一些不必要的麻烦(例如数据太多,植物还没来得及生长完洒水器就开始工作)
|
||||
#mc的时间范围为0-23999ticks,1秒=20ticks
|
||||
#插件兼容
|
||||
integration:
|
||||
#收获flag为harvest 浇水种植flag为build
|
||||
Residence: false
|
||||
#收获flag为BLOCK-BREAK 浇水种植flag为BUILD
|
||||
WorldGuard: false
|
||||
#只有王国成员可以收获、浇水和种植
|
||||
Kingdoms: false
|
||||
#信任的玩家可以收获、浇水和种植
|
||||
GriefDefender: false
|
||||
|
||||
#生长时间点
|
||||
#生长时间点(tick)
|
||||
#洒水器将会在农作物全部完成生长后开始工作
|
||||
grow-time:
|
||||
- 0
|
||||
- 12000
|
||||
- 1000
|
||||
|
||||
#洒水器工作点
|
||||
sprinkler-time:
|
||||
- 200
|
||||
- 12200
|
||||
#产物品质
|
||||
quality:
|
||||
#若不启用则植物成熟阶段会掉落IA配置里的loot
|
||||
#如果关闭产物品质需要在IA物品配置内自行添加最后一阶段掉落物
|
||||
enable: true
|
||||
#默认品质权重比
|
||||
default-ratio: 17/2/1
|
||||
|
||||
#异步时间检测,此设置需要重启生效
|
||||
#启用异步时间检测会带来更好的性能但是可能会因为服务器的跳tick原因错过一些生长时间点
|
||||
async-time-check: false
|
||||
|
||||
#使用一次水桶可以补充几个洒水器水槽
|
||||
sprinkler-refill: 2
|
||||
|
||||
#生长生效的世界
|
||||
whitelist-worlds:
|
||||
- world
|
||||
|
||||
#骨粉催熟农作物进入下一阶段的概率(0-1)
|
||||
bone-meal-chance: 0.5
|
||||
#使用骨粉是否会让种植盆从湿润转为干燥
|
||||
bone-meal-consume-water: true
|
||||
#粒子效果
|
||||
particle:
|
||||
#使用骨粉成功的粒子
|
||||
success: HEART
|
||||
#使用骨粉失败的粒子
|
||||
failure: VILLAGER_ANGRY
|
||||
|
||||
#温室系统,在温室玻璃正下方的方块可以无视季节种植
|
||||
enable-greenhouse: true
|
||||
#温室玻璃有效范围
|
||||
greenhouse-range: 7
|
||||
|
||||
#植物的种植盆方块
|
||||
pot: customcrops:pot
|
||||
#植物的浇过水的种植盆方块
|
||||
watered-pot: customcrops:watered_pot
|
||||
#水壶1x1
|
||||
watering-can-1: customcrops:watering_can_1
|
||||
#水壶1x3
|
||||
watering-can-2: customcrops:watering_can_2
|
||||
#水壶1x5
|
||||
watering-can-3: customcrops:watering_can_3
|
||||
#温室玻璃方块
|
||||
greenhouse-glass: customcrops:greenhouse_glass
|
||||
#洒水器的家具
|
||||
sprinkler-1: customcrops:sprinkler_1
|
||||
#洒水器的方块的2D物品
|
||||
sprinkler-1-item: customcrops:sprinkler_1_item
|
||||
#优质洒水器的家具
|
||||
sprinkler-2: customcrops:sprinkler_2
|
||||
#优质洒水器的方块的2D物品
|
||||
sprinkler-2-item: customcrops:sprinkler_2_item
|
||||
#农作物枯萎后变成的方块,物品ID中请保留stage以保持其下方方块被破坏时,枯萎作物也被破坏的特性
|
||||
dead-crop: customcrops:crop_stage_death
|
||||
|
||||
#种植的最低和最高Y坐标
|
||||
height:
|
||||
min: 50
|
||||
max: 150
|
||||
#每个区块最大农作物数量和洒水器数量
|
||||
#是否启用限制
|
||||
enable-limit: true
|
||||
max-crops: 64
|
||||
max-sprinklers: 8
|
||||
limit:
|
||||
enable: true
|
||||
crop: 64
|
||||
sprinkler: 8
|
||||
|
||||
#记录生长判断和洒水所需的时间
|
||||
#记录生长判断和洒水所需的时间(测试性能用)
|
||||
log-time-consume: false
|
||||
|
||||
#插件兼容
|
||||
integration:
|
||||
#收获flag为harvest 浇水种植flag为build
|
||||
residence: false
|
||||
#收获flag为BLOCK-BREAK 浇水种植flag为BUILD
|
||||
worldguard: false
|
||||
#只有王国成员可以收获、浇水和种植
|
||||
kingdomsX: false
|
||||
#信任的玩家可以收获、浇水和种植
|
||||
griefdefender: false
|
||||
|
||||
|
||||
#MineDown格式Wiki
|
||||
#https://github.com/Phoenix616/MineDown
|
||||
messages:
|
||||
prefix: '&#ccfbff-#ef96c5&[CustomCrops] '
|
||||
not-a-good-place: '&f这个地方太高/太低了,请换个地方试试吧!'
|
||||
reload: '&f插件已重载.'
|
||||
force-save: '&f成功强制保存缓存信息!'
|
||||
no-such-seed: '&f此种子未在配置文件中配置!'
|
||||
wrong-season: '&f这个季节不适合这种农作物生长!'
|
||||
season-set: '&f成功设置季节为{Season}.'
|
||||
nextseason: '&f已切换到下一季节!'
|
||||
season-disabled: '&f季节系统未启用.'
|
||||
force-grow: '&f已强制生长!'
|
||||
force-water: '&f已强制洒水!'
|
||||
reach-limit-crop: '&f农作物已到达最大区块上限{Max}!'
|
||||
reach-limit-sprinkler: '&f洒水器已到达最大区块上限{Max}!'
|
||||
can-full: '&f水壶已满!'
|
||||
backup: '&f备份完成'
|
||||
spring: '&f春'
|
||||
summer: '&f夏'
|
||||
autumn: '&f秋'
|
||||
winter: '&f冬'
|
||||
#是否只有加载中的区块农作物才会生长
|
||||
#如果你不使用季节、可重复收获、巨大化农作物特性
|
||||
#插件data只会记录正在生长中某个阶段的农作物数据
|
||||
#生长到最后一阶段农作物生长数据就会清除
|
||||
#那么可以尝试设置此值为false来让数据内全部农作物生长
|
||||
#如果你使用上述三个特性中的任意一个,请不要设置为false
|
||||
#否则农作物生长到最后一阶段不会从数据中清除,过大的数据量
|
||||
#可能会导致服务器严重卡顿
|
||||
only-grow-in-loaded-chunks: true
|
||||
@@ -1,32 +1,64 @@
|
||||
#在IA配置文件中
|
||||
#农作物种子ID请以 _seeds 结尾
|
||||
#农作物生长阶段请以 _stage_X 结尾
|
||||
#生长阶段从1开始依次累加
|
||||
#若无法理解可以参考范例配置文件
|
||||
crops:
|
||||
#在IA配置文件中命名农作物时请以_seeds和_stage_X结尾,否则会无法生长和种植
|
||||
#只要遵循正确的命名规则,你可以无限自定义农作物阶段数量
|
||||
tomato:
|
||||
#每个生长点生长一个阶段的概率
|
||||
#此项目必填(0-1)
|
||||
grow-chance: 0.4
|
||||
|
||||
#适宜的生长季节,若未启用季节系统可以无视此项目
|
||||
#若启用季节则必须填写此项目
|
||||
#季节之间用逗号分隔
|
||||
#可用的季节类型spring,summer,autumn,winter
|
||||
season: spring,summer
|
||||
|
||||
#空手收获后返回第几个生长状态
|
||||
#不填写此项目则无法重复收获
|
||||
return: customcrops:tomato_stage_1
|
||||
#收获时获取的基础数量
|
||||
amount: 1~4
|
||||
#农作物收获得到的三种品质
|
||||
quality:
|
||||
1: customcrops:tomato
|
||||
2: customcrops:tomato_silver_star
|
||||
3: customcrops:tomato_golden_star
|
||||
|
||||
#巨大化植物,以极低的概率生长为另一种形态
|
||||
gigantic: customcrops:gigantic_tomato
|
||||
gigantic-chance: 0.01
|
||||
gigantic:
|
||||
block: customcrops:gigantic_tomato
|
||||
chance: 0.01
|
||||
|
||||
#生长季节
|
||||
season:
|
||||
- spring
|
||||
- summer
|
||||
|
||||
requirements:
|
||||
#适宜的生长高度
|
||||
yPos:
|
||||
- 50~100
|
||||
- 150~200
|
||||
#适宜的生长群系
|
||||
biome:
|
||||
- minecraft:plains
|
||||
#适宜的世界
|
||||
world:
|
||||
- world
|
||||
#种植此农作物需要玩家有什么权限
|
||||
permission: 'customcrops.plant.tomato'
|
||||
|
||||
cabbage:
|
||||
grow-chance: 0.8
|
||||
season: summer,autumn
|
||||
amount: 1~2
|
||||
quality:
|
||||
1: customcrops:cabbage
|
||||
2: customcrops:cabbage_silver_star
|
||||
3: customcrops:cabbage_golden_star
|
||||
gigantic: customcrops:gigantic_cabbage
|
||||
gigantic-chance: 0.02
|
||||
requirements:
|
||||
season:
|
||||
- spring
|
||||
- summer
|
||||
|
||||
grape:
|
||||
grow-chance: 0.5
|
||||
season: autumn
|
||||
amount: 2~4
|
||||
#空手收获后返回第几个生长状态
|
||||
quality:
|
||||
1: customcrops:grape
|
||||
2: customcrops:grape_silver_star
|
||||
3: customcrops:grape_golden_star
|
||||
return: customcrops:grape_stage_4
|
||||
requirements:
|
||||
season:
|
||||
- spring
|
||||
- summer
|
||||
74
src/main/resources/fertilizer.yml
Normal file
74
src/main/resources/fertilizer.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
#你可以自定义任意数量的肥料
|
||||
|
||||
#有概率一次生长两个阶段
|
||||
加速肥料:
|
||||
speed_1:
|
||||
#肥料名,用于悬浮展示
|
||||
name: '뀌'
|
||||
#生效的概率
|
||||
chance: 0.1
|
||||
#肥料在土壤中存留的生长周期数
|
||||
times: 14
|
||||
#命名空间随意,物品ID请保持一致
|
||||
item: customcrops:speed_1
|
||||
#肥料是否只有在种植前才能使用
|
||||
before-plant: true
|
||||
|
||||
speed_2:
|
||||
name: '뀍'
|
||||
chance: 0.2
|
||||
times: 14
|
||||
item: customcrops:speed_2
|
||||
before-plant: true
|
||||
speed_3:
|
||||
name: '뀎'
|
||||
chance: 0.3
|
||||
times: 14
|
||||
item: customcrops:speed_3
|
||||
before-plant: true
|
||||
|
||||
#土壤在生长点过后有一定概率仍然保持湿润
|
||||
保湿肥料:
|
||||
retaining_1:
|
||||
name: '뀉'
|
||||
chance: 0.1
|
||||
times: 28
|
||||
item: customcrops:retaining_1
|
||||
before-plant: false
|
||||
|
||||
retaining_2:
|
||||
name: '뀊'
|
||||
chance: 0.2
|
||||
times: 28
|
||||
item: customcrops:retaining_2
|
||||
before-plant: false
|
||||
|
||||
retaining_3:
|
||||
name: '뀋'
|
||||
chance: 0.3
|
||||
times: 28
|
||||
item: customcrops:retaining_3
|
||||
before-plant: false
|
||||
|
||||
#更改农作物产物三种品质的权重
|
||||
品质肥料:
|
||||
quality_1:
|
||||
name: '뀆'
|
||||
times: 28
|
||||
chance: 7/2/1
|
||||
item: customcrops:quality_1
|
||||
before-plant: true
|
||||
|
||||
quality_2:
|
||||
name: '뀇'
|
||||
times: 28
|
||||
chance: 11/6/3
|
||||
item: customcrops:quality_2
|
||||
before-plant: true
|
||||
|
||||
quality_3:
|
||||
name: '뀈'
|
||||
times: 28
|
||||
chance: 2/2/1
|
||||
item: customcrops:quality_3
|
||||
before-plant: true
|
||||
48
src/main/resources/messages.yml
Normal file
48
src/main/resources/messages.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
#MiniMessage Format
|
||||
#https://docs.adventure.kyori.net/minimessage/format.html
|
||||
messages:
|
||||
prefix: '<gradient:#ff206c:#fdee55>[CustomCrops] </gradient>'
|
||||
reload: '<white>重载成功! 耗时 <green>{time}ms'
|
||||
no-perm: '<red>权限不足!'
|
||||
lack-args: '<white>参数不足!'
|
||||
wrong-args: '参数错误!'
|
||||
spring: '春'
|
||||
summer: '夏'
|
||||
autumn: '秋'
|
||||
winter: '冬'
|
||||
sprinkler-limit: '此区块的洒水器已到达上限{max}'
|
||||
crop-limit: '此区块的农作物数量已到达上限{max}'
|
||||
not-configed: '此种子未在配置文件中配置!'
|
||||
bad-Y: '此高度不适合这种农作物生长!'
|
||||
bad-biome: '此生物群系不适合这种农作物生长!'
|
||||
bad-perm: '你还没有权限种植这种农作物呢!'
|
||||
bad-world: '这个农作物无法在这个世界生长!'
|
||||
bad-season: '当前季节不适合这种农作物生长!'
|
||||
force-grow: '成功强制 {world} 的农作物生长!'
|
||||
force-water: '成功强制 {world} 的洒水器洒水!'
|
||||
force-save: '成功强制保存缓存信息!'
|
||||
back-up: '已完成数据备份!'
|
||||
set-season: '成功切换世界 {world} 的季节为 {season}!'
|
||||
|
||||
#全息信息显示
|
||||
hologram:
|
||||
#农作物肥料信息
|
||||
grow-info:
|
||||
enable: true
|
||||
#悬浮信息高度偏移
|
||||
y-offset: 0.8
|
||||
#悬浮信息持续时间(秒)
|
||||
duration: 1
|
||||
#悬浮信息内容
|
||||
#可用变量 {fertilizer}肥料名 {times}剩余生效次数 {max_times}最大生效次数
|
||||
text: '<font:customcrops:default>{fertilizer} </font><white>{times}<gray>/<white>{max_times}'
|
||||
#洒水器信息
|
||||
sprinkler-info:
|
||||
enable: true
|
||||
y-offset: -0.2
|
||||
duration: 1
|
||||
#可用变量 {water}当前水量 {max_water}最大蓄水量
|
||||
left: '<font:customcrops:default>뀂'
|
||||
full: '뀁뀃'
|
||||
empty: '뀁뀄'
|
||||
right: '뀁뀅</font>'
|
||||
@@ -1,9 +1,10 @@
|
||||
name: CustomCrops
|
||||
version: '1.4.8'
|
||||
version: '1.5.0-SNAPSHOT'
|
||||
main: net.momirealms.customcrops.CustomCrops
|
||||
api-version: 1.16
|
||||
depend:
|
||||
- ItemsAdder
|
||||
- ProtocolLib
|
||||
softdepend:
|
||||
- PlaceholderAPI
|
||||
- Residence
|
||||
@@ -14,5 +15,3 @@ authors: [ XiaoMoMi ]
|
||||
commands:
|
||||
customcrops:
|
||||
usage: /customcrops <args>
|
||||
permission-message: No Permission
|
||||
permission: customcrops.admin
|
||||
17
src/main/resources/season.yml
Normal file
17
src/main/resources/season.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
season:
|
||||
#是否使用季节限制
|
||||
#非植物季节则无法耕种,过了季节则枯死
|
||||
enable: true
|
||||
|
||||
auto-season-change:
|
||||
#是否启用内置季节交替
|
||||
#启用此设置将根据服务器单个世界的游戏天数自动计算当前季节
|
||||
enable: true
|
||||
#每个季节的时长(天)
|
||||
duration: 28
|
||||
|
||||
greenhouse:
|
||||
#温室系统,在温室玻璃正下方的方块可以无视季节种植
|
||||
enable: true
|
||||
#温室玻璃有效范围
|
||||
range: 5
|
||||
Reference in New Issue
Block a user