first commit
This commit is contained in:
commit
a2935ad53d
31 changed files with 3127 additions and 0 deletions
170
.gitignore
vendored
Normal file
170
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/intellij,java,gradle
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij,java,gradle
|
||||||
|
|
||||||
|
### Intellij ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Intellij Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||||
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
|
# SonarQube Plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||||
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
|
# Markdown Navigator plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||||
|
.idea/**/markdown-navigator.xml
|
||||||
|
.idea/**/markdown-navigator-enh.xml
|
||||||
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
|
# Cache file creation bug
|
||||||
|
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||||
|
.idea/$CACHE_FILE$
|
||||||
|
|
||||||
|
# CodeStream plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||||
|
.idea/codestream.xml
|
||||||
|
|
||||||
|
# Azure Toolkit for IntelliJ plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||||
|
.idea/**/azureSettings.xml
|
||||||
|
|
||||||
|
### Java ###
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
replay_pid*
|
||||||
|
|
||||||
|
### Gradle ###
|
||||||
|
.gradle
|
||||||
|
**/build/
|
||||||
|
!src/**/build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Avoid ignore Gradle wrappper properties
|
||||||
|
!gradle-wrapper.properties
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
# Eclipse Gradle plugin generated files
|
||||||
|
# Eclipse Core
|
||||||
|
.project
|
||||||
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
### Gradle Patch ###
|
||||||
|
# Java heap dump
|
||||||
|
*.hprof
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/intellij,java,gradle
|
||||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="21" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
.idea/modules.xml
generated
Normal file
9
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/SnowCore.main.iml" filepath="$PROJECT_DIR$/.idea/modules/SnowCore.main.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/SnowCore.test.iml" filepath="$PROJECT_DIR$/.idea/modules/SnowCore.test.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
13
.idea/modules/SnowCore.main.iml
generated
Normal file
13
.idea/modules/SnowCore.main.iml
generated
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="minecraft" name="Minecraft">
|
||||||
|
<configuration>
|
||||||
|
<autoDetectTypes>
|
||||||
|
<platformType>ADVENTURE</platformType>
|
||||||
|
</autoDetectTypes>
|
||||||
|
<projectReimportVersion>1</projectReimportVersion>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
13
.idea/modules/SnowCore.test.iml
generated
Normal file
13
.idea/modules/SnowCore.test.iml
generated
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="minecraft" name="Minecraft">
|
||||||
|
<configuration>
|
||||||
|
<autoDetectTypes>
|
||||||
|
<platformType>ADVENTURE</platformType>
|
||||||
|
</autoDetectTypes>
|
||||||
|
<projectReimportVersion>1</projectReimportVersion>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
73
build.gradle
Normal file
73
build.gradle
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
|
id "io.github.goooler.shadow" version "8.1.8"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'ovh.sad'
|
||||||
|
version = '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = "papermc-repo"
|
||||||
|
url = "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
}
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
maven {
|
||||||
|
url = 'https://repo.extendedclip.com/releases/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.build {
|
||||||
|
dependsOn shadowJar
|
||||||
|
}
|
||||||
|
tasks.shadowJar {
|
||||||
|
archiveClassifier.set("shaded") // removes "-all"
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
relocate("dev.triumphteam.gui", "ovh.sad.snowcore.gui")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT")
|
||||||
|
implementation "dev.triumphteam:triumph-gui:3.1.13"
|
||||||
|
compileOnly("com.github.MilkBowl:VaultAPI:1.7") { exclude( group: 'org.bukkit', module: 'bukkit' ) }
|
||||||
|
compileOnly 'me.clip:placeholderapi:2.12.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
// Configure the Minecraft version for our task.
|
||||||
|
// This is the only required configuration besides applying the plugin.
|
||||||
|
// Your plugin's jar (or shadowJar if present) will be used automatically.
|
||||||
|
minecraftVersion("1.21")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def targetJavaVersion = 21
|
||||||
|
java {
|
||||||
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
|
sourceCompatibility = javaVersion
|
||||||
|
targetCompatibility = javaVersion
|
||||||
|
if (JavaVersion.current() < javaVersion) {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
|
||||||
|
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||||
|
options.release.set(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
def props = [version: version]
|
||||||
|
inputs.properties props
|
||||||
|
filteringCharset 'UTF-8'
|
||||||
|
filesMatching('plugin.yml') {
|
||||||
|
expand props
|
||||||
|
}
|
||||||
|
}
|
||||||
0
gradle.properties
Normal file
0
gradle.properties
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
249
gradlew
vendored
Executable file
249
gradlew
vendored
Executable file
|
|
@ -0,0 +1,249 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
gradlew.bat
vendored
Normal file
92
gradlew.bat
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
1
settings.gradle
Normal file
1
settings.gradle
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'SnowCore'
|
||||||
179
src/main/java/ovh/sad/snowcore/Area.java
Normal file
179
src/main/java/ovh/sad/snowcore/Area.java
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
package ovh.sad.snowcore;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.Ageable;
|
||||||
|
import org.bukkit.block.data.Bisected;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Waterlogged;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class Area {
|
||||||
|
static class MaterialWithChance {
|
||||||
|
public Material material;
|
||||||
|
public float chance; // in precentage 1 to 100, 33.33 works aswell
|
||||||
|
|
||||||
|
public MaterialWithChance(Material material, float chance) {
|
||||||
|
this.material = material;
|
||||||
|
this.chance = chance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Location positionOne;
|
||||||
|
private final Location positionTwo;
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
private final MaterialWithChance[] materials;
|
||||||
|
public final float airPercentage;
|
||||||
|
|
||||||
|
public Area(String name, MaterialWithChance[] materials,
|
||||||
|
Location positionOne,
|
||||||
|
Location positionTwo,
|
||||||
|
float airPercentage
|
||||||
|
) {
|
||||||
|
this.name = name;
|
||||||
|
this.materials = materials;
|
||||||
|
this.positionOne = positionOne;
|
||||||
|
this.positionTwo = positionTwo;
|
||||||
|
this.airPercentage = airPercentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void regen(World world) {
|
||||||
|
|
||||||
|
int minX = Math.min(positionOne.getBlockX(), positionTwo.getBlockX());
|
||||||
|
int minY = Math.min(positionOne.getBlockY(), positionTwo.getBlockY());
|
||||||
|
int minZ = Math.min(positionOne.getBlockZ(), positionTwo.getBlockZ());
|
||||||
|
|
||||||
|
int maxX = Math.max(positionOne.getBlockX(), positionTwo.getBlockX());
|
||||||
|
int maxZ = Math.max(positionOne.getBlockZ(), positionTwo.getBlockZ());
|
||||||
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
for (int x = minX; x <= maxX; x++) {
|
||||||
|
for (int z = minZ; z <= maxZ; z++) {
|
||||||
|
|
||||||
|
Block base = world.getBlockAt(x, minY, z);
|
||||||
|
if (!isReplaceable(base.getType())) continue;
|
||||||
|
|
||||||
|
if (airPercentage > 0 && random.nextInt(100) < airPercentage) {
|
||||||
|
|
||||||
|
for (int y = minY; y <= minY + 3; y++) {
|
||||||
|
Block b = world.getBlockAt(x, y, z);
|
||||||
|
if (isReplaceable(b.getType())) {
|
||||||
|
b.setType(Material.AIR, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalWeight = 0;
|
||||||
|
for (MaterialWithChance m : materials) {
|
||||||
|
totalWeight += m.chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roll = random.nextInt(totalWeight);
|
||||||
|
int current = 0;
|
||||||
|
MaterialWithChance chosen = null;
|
||||||
|
|
||||||
|
for (MaterialWithChance m : materials) {
|
||||||
|
current += m.chance;
|
||||||
|
if (roll < current) {
|
||||||
|
chosen = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chosen == null) continue;
|
||||||
|
|
||||||
|
for (int y = minY; y <= minY + 3; y++) {
|
||||||
|
Block b = world.getBlockAt(x, y, z);
|
||||||
|
if (isReplaceable(b.getType())) {
|
||||||
|
b.setType(Material.AIR, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDoubleHeight(chosen.material)) {
|
||||||
|
placeBisected(world, x, minY, z, chosen.material);
|
||||||
|
} else {
|
||||||
|
base.setType(chosen.material, false);
|
||||||
|
|
||||||
|
BlockData data = base.getBlockData();
|
||||||
|
|
||||||
|
if(data instanceof Ageable ageable) {
|
||||||
|
ageable.setAge(1+random.nextInt(ageable.getMaximumAge()));
|
||||||
|
base.setBlockData(ageable, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data instanceof Waterlogged waterlogged) {
|
||||||
|
waterlogged.setWaterlogged(false);
|
||||||
|
base.setBlockData(waterlogged, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data instanceof org.bukkit.block.data.type.FlowerBed petals) {
|
||||||
|
int max = petals.getMaximumFlowerAmount();
|
||||||
|
petals.setFlowerAmount(random.nextInt(1, max + 1));
|
||||||
|
base.setBlockData(petals, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private boolean isReplaceable(Material m) {
|
||||||
|
if (m == Material.AIR) return true;
|
||||||
|
|
||||||
|
for (MaterialWithChance allowed : materials) {
|
||||||
|
if (allowed.material == m) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private static void placeBisected(World world, int x, int y, int z, Material mat) {
|
||||||
|
Block bottom = world.getBlockAt(x, y, z);
|
||||||
|
Block top = world.getBlockAt(x, y + 1, z);
|
||||||
|
|
||||||
|
bottom.setType(mat, false);
|
||||||
|
top.setType(mat, false);
|
||||||
|
|
||||||
|
Bisected lower = (Bisected) bottom.getBlockData();
|
||||||
|
Bisected upper = (Bisected) top.getBlockData();
|
||||||
|
|
||||||
|
lower.setHalf(Bisected.Half.BOTTOM);
|
||||||
|
upper.setHalf(Bisected.Half.TOP);
|
||||||
|
|
||||||
|
bottom.setBlockData(lower, false);
|
||||||
|
top.setBlockData(upper, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAirPercentage(World world) {
|
||||||
|
int minX = Math.min(positionOne.getBlockX(), positionTwo.getBlockX());
|
||||||
|
int maxX = Math.max(positionOne.getBlockX(), positionTwo.getBlockX());
|
||||||
|
|
||||||
|
int minY = Math.min(positionOne.getBlockY(), positionTwo.getBlockY());
|
||||||
|
|
||||||
|
int minZ = Math.min(positionOne.getBlockZ(), positionTwo.getBlockZ());
|
||||||
|
int maxZ = Math.max(positionOne.getBlockZ(), positionTwo.getBlockZ());
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
int airCount = 0;
|
||||||
|
|
||||||
|
for (int x = minX; x <= maxX; x++) {
|
||||||
|
for (int z = minZ; z <= maxZ; z++) {
|
||||||
|
total++;
|
||||||
|
Block block = world.getBlockAt(x, minY, z);
|
||||||
|
if (block.getType() == Material.AIR) airCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total == 0) return 0f;
|
||||||
|
|
||||||
|
return (airCount / (float) total) * 100f;
|
||||||
|
}
|
||||||
|
private static boolean isDoubleHeight(Material m) {
|
||||||
|
return m.createBlockData() instanceof Bisected;
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/main/java/ovh/sad/snowcore/Prices.java
Normal file
115
src/main/java/ovh/sad/snowcore/Prices.java
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package ovh.sad.snowcore;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
import ovh.sad.snowcore.items.Tool;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Prices {
|
||||||
|
|
||||||
|
public static final Map<Material, Double> SELL_PRICES = new HashMap<>();
|
||||||
|
private static final Map<Material, Integer> toolPrices = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Snow (very common / farmable)
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.SNOWBALL, 0.5); // safe value
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Cactus Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.CACTUS_FLOWER, 4.0);
|
||||||
|
SELL_PRICES.put(Material.PEONY, 4.0);
|
||||||
|
SELL_PRICES.put(Material.PINK_TULIP, 4.0);
|
||||||
|
SELL_PRICES.put(Material.CACTUS, 7.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Spruce Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.WILDFLOWERS, 1.0);
|
||||||
|
SELL_PRICES.put(Material.SPRUCE_SAPLING, 10.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Pink Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.PINK_PETALS, 1.0);
|
||||||
|
SELL_PRICES.put(Material.ALLIUM, 7.0);
|
||||||
|
SELL_PRICES.put(Material.CHERRY_SAPLING, 20.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
White Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.OXEYE_DAISY, 2.0);
|
||||||
|
SELL_PRICES.put(Material.LILY_OF_THE_VALLEY, 2.0);
|
||||||
|
SELL_PRICES.put(Material.CLOSED_EYEBLOSSOM, 10.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Gray Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.DEAD_FIRE_CORAL, 4.0);
|
||||||
|
SELL_PRICES.put(Material.DEAD_TUBE_CORAL, 4.0);
|
||||||
|
SELL_PRICES.put(Material.DEAD_HORN_CORAL, 4.0);
|
||||||
|
SELL_PRICES.put(Material.DEAD_BRAIN_CORAL_FAN, 4.0);
|
||||||
|
SELL_PRICES.put(Material.OPEN_EYEBLOSSOM, 20.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Red Area
|
||||||
|
========================= */
|
||||||
|
SELL_PRICES.put(Material.ROSE_BUSH, 3.0);
|
||||||
|
SELL_PRICES.put(Material.POPPY, 3.0);
|
||||||
|
SELL_PRICES.put(Material.RED_MUSHROOM, 3.0);
|
||||||
|
SELL_PRICES.put(Material.CRIMSON_FUNGUS, 10.0);
|
||||||
|
|
||||||
|
|
||||||
|
/* Farming areas */
|
||||||
|
|
||||||
|
SELL_PRICES.put(Material.BEETROOT_SEEDS, 0.5);
|
||||||
|
SELL_PRICES.put(Material.POTATO, 1.0);
|
||||||
|
SELL_PRICES.put(Material.CARROT, 1.0);
|
||||||
|
SELL_PRICES.put(Material.WHEAT_SEEDS, 0.5);
|
||||||
|
|
||||||
|
SELL_PRICES.put(Material.POISONOUS_POTATO, 10.0 );
|
||||||
|
SELL_PRICES.put(Material.WHEAT, 4.0);
|
||||||
|
SELL_PRICES.put(Material.BEETROOT, 2.0);
|
||||||
|
|
||||||
|
|
||||||
|
// Load hoe prices
|
||||||
|
List<? extends Tool<?>> hoes = Hoe.HoeDefinitions.ORDERED;
|
||||||
|
int[] hoePrices = {0, 1000, 5000, 10000, 40000, 200000}; // adjust if needed
|
||||||
|
for (int i = 0; i < hoes.size() && i < hoePrices.length; i++) {
|
||||||
|
toolPrices.put(hoes.get(i).material, hoePrices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load shovel prices
|
||||||
|
List<? extends Tool<?>> shovels = Shovel.ShovelDefinitions.ORDERED;
|
||||||
|
int[] shovelPrices = {0, 1000, 5000, 10000, 40000, 200000}; // adjust if needed
|
||||||
|
for (int i = 0; i < shovels.size() && i < shovelPrices.length; i++) {
|
||||||
|
toolPrices.put(shovels.get(i).material, shovelPrices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getToolBuyPrice(Tool<?> tool) {
|
||||||
|
return toolPrices.get(tool.material);
|
||||||
|
}
|
||||||
|
public static boolean hasSellPrice(Material mat) {
|
||||||
|
return SELL_PRICES.containsKey(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getSellPrice(Material mat) {
|
||||||
|
return SELL_PRICES.get(mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
318
src/main/java/ovh/sad/snowcore/Snowcore.java
Normal file
318
src/main/java/ovh/sad/snowcore/Snowcore.java
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
package ovh.sad.snowcore;
|
||||||
|
|
||||||
|
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.Style;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
import net.milkbowl.vault.economy.Economy;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.type.Snow;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import ovh.sad.snowcore.commands.RegenCommand;
|
||||||
|
import ovh.sad.snowcore.commands.SellCommand;
|
||||||
|
import ovh.sad.snowcore.commands.SnowifyCommand;
|
||||||
|
import ovh.sad.snowcore.commands.ViewItemsCommand;
|
||||||
|
import ovh.sad.snowcore.listeners.BreakListener;
|
||||||
|
import ovh.sad.snowcore.listeners.InteractListener;
|
||||||
|
import ovh.sad.snowcore.listeners.PlaceListener;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
|
||||||
|
public final class Snowcore extends JavaPlugin {
|
||||||
|
public static Economy econ = null;
|
||||||
|
|
||||||
|
public static Area[] areas = new Area[]{
|
||||||
|
new Area(
|
||||||
|
"Cactus Area",
|
||||||
|
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.CACTUS_FLOWER, 28.57f),
|
||||||
|
new Area.MaterialWithChance(Material.PEONY, 28.57f),
|
||||||
|
new Area.MaterialWithChance(Material.PINK_TULIP, 28.57f),
|
||||||
|
new Area.MaterialWithChance(Material.CACTUS, 14.29f)
|
||||||
|
},
|
||||||
|
new Location(null, 80, 129, 161),
|
||||||
|
new Location(null, 73, 131, 184),
|
||||||
|
15
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Spruce Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.SPRUCE_SAPLING, 10),
|
||||||
|
new Area.MaterialWithChance(Material.WILDFLOWERS, 80)
|
||||||
|
},
|
||||||
|
new Location(null, 64, 129, 161),
|
||||||
|
new Location(null, 69, 129, 170),
|
||||||
|
5
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Pink Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.PINK_PETALS, 80),
|
||||||
|
new Area.MaterialWithChance(Material.ALLIUM, 15),
|
||||||
|
new Area.MaterialWithChance(Material.CHERRY_SAPLING, 5)
|
||||||
|
},
|
||||||
|
new Location(null, 64, 130, 174),
|
||||||
|
new Location(null, 69, 129, 184),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"White Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.OXEYE_DAISY, 45),
|
||||||
|
new Area.MaterialWithChance(Material.LILY_OF_THE_VALLEY, 45),
|
||||||
|
new Area.MaterialWithChance(Material.CLOSED_EYEBLOSSOM, 10)
|
||||||
|
|
||||||
|
},
|
||||||
|
new Location(null, 69, 129, 189),
|
||||||
|
new Location(null, 64, 129, 198),
|
||||||
|
10
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Gray Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.DEAD_FIRE_CORAL, 23.75f),
|
||||||
|
new Area.MaterialWithChance(Material.DEAD_TUBE_CORAL, 23.75f),
|
||||||
|
new Area.MaterialWithChance(Material.DEAD_HORN_CORAL, 23.75f),
|
||||||
|
new Area.MaterialWithChance(Material.DEAD_BRAIN_CORAL_FAN, 23.75f),
|
||||||
|
new Area.MaterialWithChance(Material.OPEN_EYEBLOSSOM, 5f)
|
||||||
|
},
|
||||||
|
new Location(null, 69, 129, 202),
|
||||||
|
new Location(null, 64, 129, 211),
|
||||||
|
20
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Red Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.ROSE_BUSH, 30),
|
||||||
|
new Area.MaterialWithChance(Material.POPPY, 30),
|
||||||
|
new Area.MaterialWithChance(Material.RED_MUSHROOM, 30),
|
||||||
|
new Area.MaterialWithChance(Material.CRIMSON_FUNGUS, 10)
|
||||||
|
|
||||||
|
},
|
||||||
|
new Location(null, 73, 129, 189),
|
||||||
|
new Location(null, 80, 131, 211),
|
||||||
|
30
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Wheat & Beetroot Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.WHEAT, 50),
|
||||||
|
new Area.MaterialWithChance(Material.BEETROOTS, 50)
|
||||||
|
},
|
||||||
|
new Location(null, 43, 129, 184),
|
||||||
|
new Location(null, 59, 129, 161),
|
||||||
|
35
|
||||||
|
),
|
||||||
|
new Area(
|
||||||
|
"Carrot & Potato Area",
|
||||||
|
new Area.MaterialWithChance[]{
|
||||||
|
new Area.MaterialWithChance(Material.CARROTS, 50),
|
||||||
|
new Area.MaterialWithChance(Material.POTATOES, 50)
|
||||||
|
},
|
||||||
|
new Location(null, 43, 129, 189),
|
||||||
|
new Location(null, 59, 129, 211),
|
||||||
|
35
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void snowify(World world, Location pos1, Location pos2) {
|
||||||
|
int minX = Math.min(pos1.getBlockX(), pos2.getBlockX());
|
||||||
|
int maxX = Math.max(pos1.getBlockX(), pos2.getBlockX());
|
||||||
|
int minY = Math.min(pos1.getBlockY(), pos2.getBlockY());
|
||||||
|
int maxY = Math.max(pos1.getBlockY(), pos2.getBlockY());
|
||||||
|
int minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());
|
||||||
|
int maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());
|
||||||
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
for (int x = minX; x <= maxX; x++) {
|
||||||
|
for (int z = minZ; z <= maxZ; z++) {
|
||||||
|
for (int y = maxY; y >= minY; y--) {
|
||||||
|
Block block = world.getBlockAt(x, y, z);
|
||||||
|
|
||||||
|
// Only care about full snow blocks as the base
|
||||||
|
if (block.getType() != Material.SNOW_BLOCK) continue;
|
||||||
|
|
||||||
|
Block above = world.getBlockAt(x, y + 1, z);
|
||||||
|
Material aboveType = above.getType();
|
||||||
|
|
||||||
|
if (aboveType == Material.AIR) {
|
||||||
|
if (random.nextInt(100) < 35) {
|
||||||
|
above.setType(Material.SNOW, false);
|
||||||
|
Snow snow = (Snow) above.getBlockData();
|
||||||
|
|
||||||
|
int layers = random.nextInt(1, 5); // 1–4
|
||||||
|
snow.setLayers(Math.min(layers, snow.getMaximumLayers()));
|
||||||
|
above.setBlockData(snow, false);
|
||||||
|
}
|
||||||
|
} else if (aboveType == Material.SNOW) {
|
||||||
|
if (random.nextInt(100) < 35) {
|
||||||
|
Snow snow = (Snow) above.getBlockData();
|
||||||
|
|
||||||
|
int add = random.nextInt(1, 5); // 1–4
|
||||||
|
int max = snow.getMaximumLayers();
|
||||||
|
|
||||||
|
snow.setLayers(Math.min(snow.getLayers() + add, max));
|
||||||
|
above.setBlockData(snow, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentLogger LOGGER;
|
||||||
|
public static JavaPlugin PLUGIN;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
LOGGER = this.getComponentLogger();
|
||||||
|
PLUGIN = this;
|
||||||
|
|
||||||
|
BasicCommand regen = new RegenCommand();
|
||||||
|
BasicCommand snowify = new SnowifyCommand();
|
||||||
|
BasicCommand sell = new SellCommand();
|
||||||
|
|
||||||
|
BasicCommand viewitems = new ViewItemsCommand();
|
||||||
|
RegisteredServiceProvider<Economy> rsp =
|
||||||
|
getServer().getServicesManager().getRegistration(Economy.class);
|
||||||
|
|
||||||
|
if (rsp == null) {
|
||||||
|
getLogger().severe("No Vault economy provider found!");
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
||||||
|
new SnowcoreExpansion(this).register();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Bukkit.getPluginManager().isPluginEnabled("Vault")) {
|
||||||
|
econ = rsp.getProvider();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
registerCommand("regen", regen);
|
||||||
|
registerCommand("sell", sell);
|
||||||
|
registerCommand("snowify", snowify);
|
||||||
|
registerCommand("viewitems", viewitems);
|
||||||
|
|
||||||
|
getServer().getPluginManager().registerEvents(new BreakListener(), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new PlaceListener(), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new InteractListener(), this);
|
||||||
|
} catch(Exception e) {
|
||||||
|
LOGGER.error(Component.text("You are most likely restarting the plugin via /plm restart snowcore. Please don't do this, commands will not be registered."));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info(Component.text("SNOWCORE - good morning!", Style.style(TextColor.color(0, 255, 0))));
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
World world = Bukkit.getWorld("world");
|
||||||
|
|
||||||
|
for(Area area : areas) {
|
||||||
|
if (area.getAirPercentage(world) > 65) {
|
||||||
|
area.regen(world);
|
||||||
|
|
||||||
|
final Component areaReplenish = MiniMessage.miniMessage().deserialize(
|
||||||
|
"<rainbow><bold>‧₊˚❀༉‧₊˚.</rainbow> <white>Seems like the <area> area has been replenished..</white> <rainbow><bold>‧₊˚❀༉‧₊˚.</rainbow>",
|
||||||
|
Placeholder.unparsed("area", area.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||||
|
player.sendActionBar(areaReplenish);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(this, 0L, 10L); // 0L delay, 200L = 10s
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (random.nextInt(100) < 15) {
|
||||||
|
final Component snowing = MiniMessage.miniMessage().deserialize(
|
||||||
|
"<blue><bold>❄❄❄</blue> <white>It seems to be snowing..</white>"
|
||||||
|
);
|
||||||
|
|
||||||
|
World world = Bukkit.getWorld("world");
|
||||||
|
Snowcore.snowify(
|
||||||
|
world,
|
||||||
|
new Location(world, 39, 127, 157),
|
||||||
|
new Location(world, 8, 139, 215)
|
||||||
|
);
|
||||||
|
|
||||||
|
Bukkit.broadcast(snowing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(this, 0L, 100L); // 0L delay, 200L = 10s
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int fortuneToDrops(int fortune, int drops) {
|
||||||
|
if (fortune <= 0) return drops;
|
||||||
|
|
||||||
|
// Clamp fortune to 1-20
|
||||||
|
fortune = Math.min(Math.max(fortune, 1), 20);
|
||||||
|
|
||||||
|
// Base chance multiplier
|
||||||
|
double multiplier = 1.0 + Math.pow(fortune, 1.3) / 10.0;
|
||||||
|
|
||||||
|
// Apply multiplier to original drops
|
||||||
|
int newDrops = (int) Math.round(drops * multiplier);
|
||||||
|
|
||||||
|
return Math.max(newDrops, drops); // never return less than original
|
||||||
|
}
|
||||||
|
public static int getLevelFromExp(int exp) {
|
||||||
|
// EXP = 5 * L^2 -> L = sqrt(exp / 5)
|
||||||
|
return (int) Math.floor(Math.sqrt(exp / 5.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendActionBar(Player player, Component message) {
|
||||||
|
Component component = MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red><bold>❌</bold> "
|
||||||
|
).append(message);
|
||||||
|
player.sendActionBar(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sellInventory(Player player) {
|
||||||
|
var inv = player.getInventory();
|
||||||
|
|
||||||
|
double finalPrice = 0d;
|
||||||
|
|
||||||
|
for (int slot = 0; slot < 35; slot++) {
|
||||||
|
ItemStack item = inv.getItem(slot);
|
||||||
|
|
||||||
|
if (item == null || item.getType().isAir()) continue;
|
||||||
|
|
||||||
|
boolean prices = Prices.hasSellPrice(item.getType());
|
||||||
|
|
||||||
|
if(prices) {
|
||||||
|
double price = Prices.getSellPrice(item.getType()) * item.getAmount();
|
||||||
|
|
||||||
|
finalPrice += price;
|
||||||
|
|
||||||
|
inv.setItem(slot, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Snowcore.econ.depositPlayer(player, finalPrice);
|
||||||
|
player.sendMessage(Component.text("Sold items for §a" + finalPrice + "§r!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
LOGGER.info(Component.text("SNOWCORE - good night.", Style.style(TextColor.color(255, 0, 0))));
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/main/java/ovh/sad/snowcore/SnowcoreExpansion.java
Normal file
79
src/main/java/ovh/sad/snowcore/SnowcoreExpansion.java
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
package ovh.sad.snowcore;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import ovh.sad.snowcore.items.ToolUtils;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
|
||||||
|
public class SnowcoreExpansion extends PlaceholderExpansion {
|
||||||
|
private final Snowcore plugin; //
|
||||||
|
|
||||||
|
public SnowcoreExpansion(Snowcore plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getAuthor() {
|
||||||
|
return String.join(", ", plugin.getPluginMeta().getAuthors());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getIdentifier() {
|
||||||
|
return "snowcore";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getVersion() {
|
||||||
|
return plugin.getPluginMeta().getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean persist() {
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String onRequest(OfflinePlayer oplayer, @NotNull String params) {
|
||||||
|
if (params.equalsIgnoreCase("tool_level")) {
|
||||||
|
Player player = oplayer.getPlayer();
|
||||||
|
if (player != null) {
|
||||||
|
ItemStack item = player.getInventory().getItemInMainHand();
|
||||||
|
Material type = item.getType();
|
||||||
|
|
||||||
|
if (Hoe.HoeDefinitions.ALL_HOES.containsKey(type)
|
||||||
|
|| Shovel.ShovelDefinitions.ALL_SHOVELS.containsKey(type)) {
|
||||||
|
|
||||||
|
int level = ToolUtils.getLevel(item);
|
||||||
|
|
||||||
|
// Clamp between 1 and 80
|
||||||
|
int clampedLevel = Math.max(1, Math.min(80, level));
|
||||||
|
|
||||||
|
// Interpolate hue (0° red → 270° violet)
|
||||||
|
float hue = (clampedLevel - 1) / 79.0f * 270f;
|
||||||
|
|
||||||
|
java.awt.Color color = java.awt.Color.getHSBColor(hue / 360f, 1f, 1f);
|
||||||
|
|
||||||
|
String hex = String.format("#%02x%02x%02x",
|
||||||
|
color.getRed(),
|
||||||
|
color.getGreen(),
|
||||||
|
color.getBlue());
|
||||||
|
|
||||||
|
return net.md_5.bungee.api.ChatColor.of(hex) + "❁ " + level;
|
||||||
|
} else {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/main/java/ovh/sad/snowcore/commands/RegenCommand.java
Normal file
25
src/main/java/ovh/sad/snowcore/commands/RegenCommand.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ovh.sad.snowcore.commands;
|
||||||
|
|
||||||
|
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.Area;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
public class RegenCommand implements BasicCommand {
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSourceStack source, String[] args) {
|
||||||
|
for(Area area: Snowcore.areas) {
|
||||||
|
area.regen(Objects.requireNonNull(source.getExecutor()).getWorld());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String permission() {
|
||||||
|
return "snowcore.regen_areas";
|
||||||
|
}
|
||||||
|
}
|
||||||
123
src/main/java/ovh/sad/snowcore/commands/SellCommand.java
Normal file
123
src/main/java/ovh/sad/snowcore/commands/SellCommand.java
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
package ovh.sad.snowcore.commands;
|
||||||
|
|
||||||
|
import dev.triumphteam.gui.builder.item.ItemBuilder;
|
||||||
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
|
import dev.triumphteam.gui.guis.GuiItem;
|
||||||
|
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.Prices;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
public class SellCommand implements BasicCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSourceStack source, String[] args) {
|
||||||
|
AtomicBoolean sold = new AtomicBoolean(false);
|
||||||
|
Gui gui = Gui.gui()
|
||||||
|
.title(Component.text("Sell Items"))
|
||||||
|
.rows(6)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gui.setDefaultClickAction(event -> {
|
||||||
|
if (event.getSlot() >= 45) event.setCancelled(true); // only block bottom row
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
GuiItem pane = ItemBuilder.from(Material.BLACK_STAINED_GLASS_PANE)
|
||||||
|
.name(Component.text(" "))
|
||||||
|
.asGuiItem();
|
||||||
|
|
||||||
|
// Fill entire bottom row
|
||||||
|
for (int col = 1; col <= 9; col++) {
|
||||||
|
gui.setItem(6, col, pane);
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiItem confirm = ItemBuilder.from(Material.GREEN_WOOL)
|
||||||
|
.name(Component.text("§aConfirm Sell"))
|
||||||
|
.asGuiItem(event -> {
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
|
||||||
|
sellItemsFromInv(sold, player, event.getInventory());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cancel (red wool)
|
||||||
|
GuiItem cancel = ItemBuilder.from(Material.RED_WOOL)
|
||||||
|
.name(Component.text("§cCancel"))
|
||||||
|
.asGuiItem(event -> {
|
||||||
|
Player player = (Player)event.getWhoClicked();
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.closeInventory();
|
||||||
|
});
|
||||||
|
|
||||||
|
gui.setItem(6, 4, confirm);
|
||||||
|
|
||||||
|
gui.setItem(6, 6, cancel);
|
||||||
|
|
||||||
|
gui.setCloseGuiAction(event -> {
|
||||||
|
Player player = (Player) event.getPlayer();
|
||||||
|
UUID id = player.getUniqueId();
|
||||||
|
|
||||||
|
// If they sold, DON'T return items
|
||||||
|
if (!sold.get()) {
|
||||||
|
sellItemsFromInv(sold, player, event.getInventory());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gui.open((Player) Objects.requireNonNull(source.getExecutor()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sellItemsFromInv(AtomicBoolean sold, Player player, Inventory inventory) {
|
||||||
|
sold.set(true); // mark as sold
|
||||||
|
|
||||||
|
var inv = inventory;
|
||||||
|
|
||||||
|
double finalPrice = 0d;
|
||||||
|
|
||||||
|
for (int slot = 0; slot < 45; slot++) {
|
||||||
|
ItemStack item = inv.getItem(slot);
|
||||||
|
|
||||||
|
if (item == null || item.getType().isAir()) continue;
|
||||||
|
|
||||||
|
boolean prices = Prices.hasSellPrice(item.getType());
|
||||||
|
|
||||||
|
if(!prices) {
|
||||||
|
player.getInventory().addItem(item);
|
||||||
|
inv.setItem(slot, null);
|
||||||
|
} else {
|
||||||
|
double price = Prices.getSellPrice(item.getType()) * item.getAmount();
|
||||||
|
|
||||||
|
finalPrice += price;
|
||||||
|
|
||||||
|
inv.setItem(slot, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Snowcore.econ.depositPlayer(player, finalPrice);
|
||||||
|
player.sendMessage(Component.text("Sold items for §a" + finalPrice + "§r!"));
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String permission() {
|
||||||
|
return "snowcore.sell";
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/main/java/ovh/sad/snowcore/commands/SnowifyCommand.java
Normal file
30
src/main/java/ovh/sad/snowcore/commands/SnowifyCommand.java
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ovh.sad.snowcore.commands;
|
||||||
|
|
||||||
|
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
public class SnowifyCommand implements BasicCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSourceStack source, String[] args) {
|
||||||
|
World world = Objects.requireNonNull(source.getExecutor()).getWorld();
|
||||||
|
Snowcore.snowify(
|
||||||
|
world,
|
||||||
|
new Location(world, 39, 127, 157),
|
||||||
|
new Location(world, 8, 139, 215)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String permission() {
|
||||||
|
return "snowcore.snowify";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ovh.sad.snowcore.commands;
|
||||||
|
|
||||||
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
|
import dev.triumphteam.gui.guis.GuiItem;
|
||||||
|
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ViewItemsCommand implements BasicCommand {
|
||||||
|
@Override
|
||||||
|
public void execute(@NotNull CommandSourceStack source, String @NotNull [] args) {
|
||||||
|
Gui gui = Gui.gui()
|
||||||
|
.title(Component.text("All obtainable items"))
|
||||||
|
.rows(6)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
Hoe.HoeDefinitions.ALL_HOES.forEach((material, hoe) -> {
|
||||||
|
gui.addItem(new GuiItem(hoe.renderItem(null)));
|
||||||
|
});
|
||||||
|
|
||||||
|
Shovel.ShovelDefinitions.ALL_SHOVELS.forEach((material, shovel) -> {
|
||||||
|
gui.addItem(new GuiItem(shovel.renderItem(null)));
|
||||||
|
});
|
||||||
|
|
||||||
|
gui.open((Player) Objects.requireNonNull(source.getExecutor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String permission() {
|
||||||
|
return "snowcore.view_items";
|
||||||
|
}
|
||||||
|
}
|
||||||
200
src/main/java/ovh/sad/snowcore/guis/UpgradeYourToolsGui.java
Normal file
200
src/main/java/ovh/sad/snowcore/guis/UpgradeYourToolsGui.java
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
package ovh.sad.snowcore.guis;
|
||||||
|
|
||||||
|
import dev.triumphteam.gui.builder.item.ItemBuilder;
|
||||||
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
|
import dev.triumphteam.gui.guis.GuiItem;
|
||||||
|
import dev.triumphteam.gui.guis.PaginatedGui;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.Style;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import ovh.sad.snowcore.Prices;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
import ovh.sad.snowcore.items.Tool;
|
||||||
|
import ovh.sad.snowcore.items.ToolUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class UpgradeYourToolsGui {
|
||||||
|
|
||||||
|
public static void open(PlayerInteractEntityEvent event) {
|
||||||
|
openHoes(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// HOES
|
||||||
|
// =========================================================
|
||||||
|
private static void openHoes(Player player) {
|
||||||
|
|
||||||
|
PaginatedGui gui = Gui.paginated()
|
||||||
|
.title(Component.text("Upgrade Your Tools - Hoes"))
|
||||||
|
.rows(3)
|
||||||
|
.pageSize(7) // only columns 2-8
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gui.setDefaultClickAction(e -> e.setCancelled(true));
|
||||||
|
|
||||||
|
fillLayout(gui);
|
||||||
|
|
||||||
|
// Add ordered hoes
|
||||||
|
for (Hoe hoe : Hoe.HoeDefinitions.ORDERED) {
|
||||||
|
gui.addItem(createToolGuiItem(hoe, player, gui));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation (bottom right)
|
||||||
|
gui.setItem(3, 9,
|
||||||
|
ItemBuilder.from(Material.ARROW)
|
||||||
|
.name(Component.text("Next → Shovels", NamedTextColor.YELLOW))
|
||||||
|
.asGuiItem(e -> {
|
||||||
|
e.setCancelled(true);
|
||||||
|
openShovels(player);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// SHOVELS
|
||||||
|
// =========================================================
|
||||||
|
private static void openShovels(Player player) {
|
||||||
|
|
||||||
|
PaginatedGui gui = Gui.paginated()
|
||||||
|
.title(Component.text("Upgrade Your Tools - Shovels"))
|
||||||
|
.rows(3)
|
||||||
|
.pageSize(7)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gui.setDefaultClickAction(e -> e.setCancelled(true));
|
||||||
|
|
||||||
|
fillLayout(gui);
|
||||||
|
|
||||||
|
for (Shovel shovel : Shovel.ShovelDefinitions.ORDERED) {
|
||||||
|
gui.addItem(createToolGuiItem(shovel, player, gui));
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.setItem(3, 9,
|
||||||
|
ItemBuilder.from(Material.ARROW)
|
||||||
|
.name(Component.text("← Previous Hoes", NamedTextColor.YELLOW))
|
||||||
|
.asGuiItem(e -> {
|
||||||
|
e.setCancelled(true);
|
||||||
|
openHoes(player);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Tool<?>> T getPreviousTool(T tool) {
|
||||||
|
int index;
|
||||||
|
if (tool instanceof Shovel) {
|
||||||
|
index = Shovel.ShovelDefinitions.ORDERED.indexOf(tool);
|
||||||
|
if (index <= 0) return null;
|
||||||
|
return (T) Shovel.ShovelDefinitions.ORDERED.get(index - 1);
|
||||||
|
} else if (tool instanceof Hoe) {
|
||||||
|
index = Hoe.HoeDefinitions.ORDERED.indexOf(tool);
|
||||||
|
if (index <= 0) return null;
|
||||||
|
return (T) Hoe.HoeDefinitions.ORDERED.get(index - 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Tool<?>> GuiItem createToolGuiItem(T tool, Player player, PaginatedGui gui) {
|
||||||
|
return new GuiItem(
|
||||||
|
tool.renderItem(null),
|
||||||
|
e -> {
|
||||||
|
e.setCancelled(true);
|
||||||
|
|
||||||
|
if (tool.material == Material.WOODEN_SHOVEL || tool.material == Material.WOODEN_HOE) {
|
||||||
|
// First tool is free
|
||||||
|
player.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<green>✔ You've been given a <name>! Enjoy Snowing.",
|
||||||
|
Placeholder.component("name", tool.name())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
player.getInventory().addItem(tool.renderItem(null));
|
||||||
|
gui.close(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get previous tool
|
||||||
|
Tool<?> previousTool = getPreviousTool(tool);
|
||||||
|
if (previousTool == null) return; // safety
|
||||||
|
|
||||||
|
// Check requirement
|
||||||
|
boolean hasPrevious = false;
|
||||||
|
for (ItemStack item : player.getInventory()) {
|
||||||
|
if (item != null && item.getType() == previousTool.material) {
|
||||||
|
hasPrevious = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasPrevious) {
|
||||||
|
player.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red>❌ Missing a requirement:</red> <previousname>",
|
||||||
|
Placeholder.component("previousname", previousTool.name())
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check economy
|
||||||
|
double balance = Snowcore.econ.getBalance(player);
|
||||||
|
Integer cost = Prices.getToolBuyPrice(tool);
|
||||||
|
|
||||||
|
if (balance >= cost) {
|
||||||
|
Snowcore.econ.withdrawPlayer(player, cost);
|
||||||
|
player.getInventory().remove(previousTool.material);
|
||||||
|
player.getInventory().addItem(tool.renderItem(null));
|
||||||
|
|
||||||
|
player.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<green>✔ Unlocked <yellow><name></yellow> for <gold>$<cost></gold> and <previousname>",
|
||||||
|
Placeholder.component("previousname", previousTool.name()),
|
||||||
|
Placeholder.component("name", tool.name()),
|
||||||
|
Placeholder.unparsed("cost", cost.toString())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
gui.close(player);
|
||||||
|
} else {
|
||||||
|
player.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red>✘ Not enough money! Need <gold>$<cost></gold>, you have <yellow>$<balance></yellow>",
|
||||||
|
Placeholder.unparsed("balance", String.valueOf(balance)),
|
||||||
|
Placeholder.unparsed("cost", cost.toString())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void fillLayout(PaginatedGui gui) {
|
||||||
|
GuiItem pane = ItemBuilder.from(Material.GRAY_STAINED_GLASS_PANE)
|
||||||
|
.name(Component.empty())
|
||||||
|
.asGuiItem(e -> e.setCancelled(true));
|
||||||
|
|
||||||
|
for (int col = 1; col <= 9; col++) {
|
||||||
|
gui.setItem(1, col, pane);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row 2 (side panes only)
|
||||||
|
gui.setItem(2, 1, pane);
|
||||||
|
gui.setItem(2, 9, pane);
|
||||||
|
|
||||||
|
// Row 3 (all panes)
|
||||||
|
for (int col = 1; col <= 9; col++) {
|
||||||
|
gui.setItem(3, col, pane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
140
src/main/java/ovh/sad/snowcore/items/Hoe.java
Normal file
140
src/main/java/ovh/sad/snowcore/items/Hoe.java
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
package ovh.sad.snowcore.items;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Hoe extends Tool<Hoe> {
|
||||||
|
private final List<Material> canBreak = new ArrayList<>();
|
||||||
|
private final List<Hoe> dependsOn = new ArrayList<>();
|
||||||
|
|
||||||
|
public Hoe(Material material, String name) {
|
||||||
|
super(material, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Hoe addCanBreaks(Collection<Material> m) {
|
||||||
|
canBreak.addAll(m);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Hoe addDepend(Hoe h) {
|
||||||
|
dependsOn.add(h);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HoeDefinitions {
|
||||||
|
public static final Hoe WOODEN_HOE = new Hoe(Material.WOODEN_HOE, "<#DCB190><b>Wooden Hoe</b></#DCB190>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 5)
|
||||||
|
.addCanBreaks(List.of( Material.SPRUCE_SAPLING, Material.WILDFLOWERS ));
|
||||||
|
public static final Hoe STONE_HOE = new Hoe(Material.STONE_HOE, "<gray><b>Stone Hoe</b><gray>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 15)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.DOUBLE_DROP, 5)
|
||||||
|
.addCanBreaks(List.of( Material.PINK_PETALS, Material.ALLIUM, Material.CHERRY_SAPLING ))
|
||||||
|
.addDepend(WOODEN_HOE);
|
||||||
|
|
||||||
|
public static final Hoe COPPER_HOE = new Hoe(Material.COPPER_HOE, "<gold><b>Copper Hoe</b><gold>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 25)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.DOUBLE_DROP, 15)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 1)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 5)
|
||||||
|
.limit(ToolUtils.EnchantmentType.WIND, 40)
|
||||||
|
.addCanBreaks(List.of(
|
||||||
|
Material.OXEYE_DAISY, Material.LILY_OF_THE_VALLEY, Material.CLOSED_EYEBLOSSOM,
|
||||||
|
Material.CARROTS, Material.POTATOES
|
||||||
|
))
|
||||||
|
.addDepend(STONE_HOE);
|
||||||
|
|
||||||
|
public static final Hoe IRON_HOE = new Hoe(Material.IRON_HOE, "<white><b>Iron Hoe</b><white>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 30)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.DOUBLE_DROP, 20)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 2)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 10)
|
||||||
|
.limit(ToolUtils.EnchantmentType.WIND, 50)
|
||||||
|
.addAbility(ToolUtils.AbilityType.JACKPOT, 3, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 1.5, 5, 50_000, false)
|
||||||
|
.addCanBreaks(
|
||||||
|
List.of(
|
||||||
|
Material.WHEAT,
|
||||||
|
Material.BEETROOTS,
|
||||||
|
Material.DEAD_FIRE_CORAL, Material.DEAD_TUBE_CORAL, Material.DEAD_HORN_CORAL, Material.DEAD_BRAIN_CORAL_FAN, Material.OPEN_EYEBLOSSOM
|
||||||
|
))
|
||||||
|
.addDepend(COPPER_HOE);
|
||||||
|
|
||||||
|
public static final Hoe DIAMOND_HOE = new Hoe(Material.DIAMOND_HOE, "<aqua><b>Diamond Hoe</b><aqua>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 30)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.DOUBLE_DROP, 20)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 3)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 20)
|
||||||
|
.limit(ToolUtils.EnchantmentType.WIND, 60)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 2.5, 5, 50_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.JACKPOT, 5, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.THREE_BY_THREE, 0, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.AUTOSELL, 1, 15, 100_000, false)
|
||||||
|
.addCanBreaks( List.of( Material.ROSE_BUSH, Material.POPPY, Material.RED_MUSHROOM, Material.CRIMSON_FUNGUS ) )
|
||||||
|
.addDepend(IRON_HOE);
|
||||||
|
|
||||||
|
public static final Hoe NETHERITE_HOE = new Hoe(Material.NETHERITE_HOE, "<dark_purple><b>Netherite Hoe</b><dark_purple>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.WIND, 40)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.DOUBLE_DROP, 30)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 4)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 30)
|
||||||
|
.limit(ToolUtils.EnchantmentType.WIND, 70)
|
||||||
|
.limit(ToolUtils.EnchantmentType.DOUBLE_DROP, 60)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 5, 5, 75_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.AUTOSELL, 1, 25, 150_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.THREE_BY_THREE, 0, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.JACKPOT, 15, 0, 15_000, true)
|
||||||
|
.addCanBreaks( List.of( Material.CACTUS_FLOWER, Material.PEONY, Material.PINK_TULIP, Material.CACTUS ) )
|
||||||
|
.addDepend(DIAMOND_HOE);
|
||||||
|
|
||||||
|
public static final HashMap<Material, Hoe> ALL_HOES = new HashMap<>(
|
||||||
|
Map.of(WOODEN_HOE.material, WOODEN_HOE,
|
||||||
|
STONE_HOE.material, STONE_HOE,
|
||||||
|
COPPER_HOE.material, COPPER_HOE,
|
||||||
|
IRON_HOE.material, IRON_HOE,
|
||||||
|
DIAMOND_HOE.material, DIAMOND_HOE,
|
||||||
|
NETHERITE_HOE.material, NETHERITE_HOE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final List<Hoe> ORDERED = List.of(
|
||||||
|
WOODEN_HOE,
|
||||||
|
STONE_HOE,
|
||||||
|
COPPER_HOE,
|
||||||
|
IRON_HOE,
|
||||||
|
DIAMOND_HOE,
|
||||||
|
NETHERITE_HOE
|
||||||
|
);
|
||||||
|
|
||||||
|
public static @Nullable Hoe getRequiredHoe(Material material) {
|
||||||
|
for (Hoe hoe : ORDERED) {
|
||||||
|
if (getAllBlocks(hoe).contains(material)) {
|
||||||
|
return hoe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Material> getAllBlocks(Hoe hoe) {
|
||||||
|
Set<Material> result = new HashSet<>();
|
||||||
|
Set<Hoe> visited = new HashSet<>();
|
||||||
|
|
||||||
|
collectBlocks(hoe, result, visited);
|
||||||
|
|
||||||
|
return new ArrayList<>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void collectBlocks(Hoe hoe, Set<Material> result, Set<Hoe> visited) {
|
||||||
|
if (!visited.add(hoe)) return; // already processed
|
||||||
|
|
||||||
|
result.addAll(hoe.canBreak);
|
||||||
|
|
||||||
|
for (Hoe parent : hoe.dependsOn) {
|
||||||
|
collectBlocks(parent, result, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
85
src/main/java/ovh/sad/snowcore/items/Shovel.java
Normal file
85
src/main/java/ovh/sad/snowcore/items/Shovel.java
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
package ovh.sad.snowcore.items;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Shovel extends Tool<Shovel> {
|
||||||
|
public Shovel(Material material, String name) {
|
||||||
|
super(material, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShovelDefinitions {
|
||||||
|
public static final Shovel WOODEN_SHOVEL = new Shovel(Material.WOODEN_SHOVEL, "<#90bbdc><b>Wooden Shovel</b></#90bbdc>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 10)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 15);
|
||||||
|
public static final Shovel STONE_SHOVEL = new Shovel(Material.STONE_SHOVEL, "<gray><b>Stone Shovel</b><gray>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 20)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.LAYER_REMOVER, 10)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 25)
|
||||||
|
.limit(ToolUtils.EnchantmentType.LAYER_REMOVER, 12);
|
||||||
|
|
||||||
|
public static final Shovel COPPER_SHOVEL = new Shovel(Material.COPPER_SHOVEL, "<#6699ff><b>Copper Shovel</b><#6699ff>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 30)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.LAYER_REMOVER, 15)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 1)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 5)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 40)
|
||||||
|
.limit(ToolUtils.EnchantmentType.LAYER_REMOVER, 20);
|
||||||
|
|
||||||
|
public static final Shovel IRON_SHOVEL = new Shovel(Material.IRON_SHOVEL, "<white><b>Iron Shovel</b><white>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 40)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.LAYER_REMOVER, 25)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 3)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 10)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 50)
|
||||||
|
.limit(ToolUtils.EnchantmentType.LAYER_REMOVER, 30)
|
||||||
|
.addAbility(ToolUtils.AbilityType.NUKE, 0, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 2, 5, 40_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.AUTOSELL, 1, 20, 15_000, false);
|
||||||
|
|
||||||
|
public static final Shovel DIAMOND_SHOVEL = new Shovel(Material.DIAMOND_SHOVEL, "<#ff5555><b>Diamond Shovel</b><#ff5555>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 50)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.LAYER_REMOVER, 35)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 4)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 10)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 60)
|
||||||
|
.limit(ToolUtils.EnchantmentType.LAYER_REMOVER, 40)
|
||||||
|
.addAbility(ToolUtils.AbilityType.NUKE, 0, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.WIFI, 2, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 3, 5, 50_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.AUTOSELL, 1, 25, 40_000, false);
|
||||||
|
|
||||||
|
public static final Shovel NETHERITE_SHOVEL = new Shovel(Material.NETHERITE_SHOVEL, "<#4dc44d><b>Netherite Shovel</b><#4dc44d>")
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.SWEEPER, 50)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.LAYER_REMOVER, 40)
|
||||||
|
.addEnchantment(ToolUtils.EnchantmentType.FORTUNE, 6)
|
||||||
|
.limit(ToolUtils.EnchantmentType.FORTUNE, 30)
|
||||||
|
.limit(ToolUtils.EnchantmentType.SWEEPER, 100)
|
||||||
|
.limit(ToolUtils.EnchantmentType.LAYER_REMOVER, 100)
|
||||||
|
.addAbility(ToolUtils.AbilityType.MULTIPLIER, 5, 5, 75_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.AUTOSELL, 1, 30, 60_000, false)
|
||||||
|
.addAbility(ToolUtils.AbilityType.NUKE, 0, 0, 0, true)
|
||||||
|
.addAbility(ToolUtils.AbilityType.WIFI, 6, 0, 0 , true);
|
||||||
|
|
||||||
|
public static final HashMap<Material, Shovel> ALL_SHOVELS = new HashMap<>(
|
||||||
|
Map.of(WOODEN_SHOVEL.material, WOODEN_SHOVEL,
|
||||||
|
STONE_SHOVEL.material, STONE_SHOVEL,
|
||||||
|
COPPER_SHOVEL.material, COPPER_SHOVEL,
|
||||||
|
IRON_SHOVEL.material, IRON_SHOVEL,
|
||||||
|
DIAMOND_SHOVEL.material, DIAMOND_SHOVEL,
|
||||||
|
NETHERITE_SHOVEL.material, NETHERITE_SHOVEL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final List<Shovel> ORDERED = List.of(
|
||||||
|
WOODEN_SHOVEL,
|
||||||
|
STONE_SHOVEL,
|
||||||
|
COPPER_SHOVEL,
|
||||||
|
IRON_SHOVEL,
|
||||||
|
DIAMOND_SHOVEL,
|
||||||
|
NETHERITE_SHOVEL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
184
src/main/java/ovh/sad/snowcore/items/Tool.java
Normal file
184
src/main/java/ovh/sad/snowcore/items/Tool.java
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
package ovh.sad.snowcore.items;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public abstract class Tool<T extends Tool<T>> {
|
||||||
|
|
||||||
|
public final Material material;
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
public final List<ToolUtils.Enchantment> definedEnchantments = new ArrayList<>();
|
||||||
|
public final Map<ToolUtils.EnchantmentType, Integer> definedEnchantLimits = new HashMap<>();
|
||||||
|
public final List<ToolUtils.Ability> definedAbilities = new ArrayList<>();
|
||||||
|
|
||||||
|
protected Tool(Material material, String name) {
|
||||||
|
this.material = material;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ItemStack renderItem(@Nullable ItemStack itemToRender) {
|
||||||
|
if(itemToRender == null) {
|
||||||
|
ItemStack item = new ItemStack(material);
|
||||||
|
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
|
||||||
|
if(meta == null) throw new Error("RenderItem errored, meta could not be found!");
|
||||||
|
|
||||||
|
Component name = MiniMessage.miniMessage().deserialize(
|
||||||
|
"<shadow:black><gray>[</gray><green>✩ 1<gray>, <blue>❁ 1</blue>]</gray></shadow> " + this.name
|
||||||
|
);
|
||||||
|
|
||||||
|
meta.setUnbreakable(true);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE);
|
||||||
|
meta.displayName(name);
|
||||||
|
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
List<ToolUtils.Ability> abilities = definedAbilities.stream().filter(a -> a.byDefault).toList();
|
||||||
|
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<gray><i>(Shift rightclick to upgrade!)"
|
||||||
|
));
|
||||||
|
|
||||||
|
lore.add(Component.text(""));
|
||||||
|
|
||||||
|
definedEnchantments.forEach(z -> {
|
||||||
|
if(z.type.usesLevel) {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<yellow> • " + z.type.name + " " + z.amount
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<white> • " + z.type.name + " (" + z.amount + "%)"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
abilities.forEach(z -> {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<aqua> ⭐ <b>" + z.type.name + "</b>, " + z.type.description.replaceAll("%maxValue%", String.valueOf(z.maxValue))
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
|
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
pdc.set(ToolUtils.EXPERIENCE, PersistentDataType.INTEGER, 1);
|
||||||
|
pdc.set(ToolUtils.TOTAL_EXPERIENCE, PersistentDataType.INTEGER, 1);
|
||||||
|
|
||||||
|
pdc.set(ToolUtils.ENCHANTMENTS,
|
||||||
|
PersistentDataType.LIST.listTypeFrom(ToolUtils.Enchantment.EMPTY_INSTANCE),
|
||||||
|
definedEnchantments);
|
||||||
|
|
||||||
|
pdc.set(ToolUtils.ABILITIES,
|
||||||
|
PersistentDataType.LIST.listTypeFrom(ToolUtils.Ability.EMPTY_INSTANCE),
|
||||||
|
definedAbilities.stream().filter(a -> a.byDefault).toList());
|
||||||
|
|
||||||
|
meta.setEnchantmentGlintOverride(true);
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
} else {
|
||||||
|
ItemStack item = itemToRender.clone();
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
|
||||||
|
if(meta == null) throw new Error("RenderItem errored, meta could not be found!");
|
||||||
|
|
||||||
|
Integer exp = ToolUtils.getExp(item);
|
||||||
|
Integer level = ToolUtils.getLevel(item);
|
||||||
|
|
||||||
|
Component name = MiniMessage.miniMessage().deserialize(
|
||||||
|
"<shadow:black><gray>[</gray><green>✩ " + exp + "<gray>, <blue>❁ " + level + "</blue>]</gray></shadow> " + this.name
|
||||||
|
);
|
||||||
|
meta.displayName(name);
|
||||||
|
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
List<ToolUtils.Ability> abilities = ToolUtils.getAbilities(item);
|
||||||
|
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<gray><i>(Shift rightclick to upgrade!)"
|
||||||
|
));
|
||||||
|
|
||||||
|
lore.add(Component.text(""));
|
||||||
|
ToolUtils.getEnchantments(item).forEach(z -> {
|
||||||
|
if(z.type.usesLevel) {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<yellow> • " + z.type.name + " " + z.amount
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<white> • " + z.type.name + " (" + z.amount + "%)"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
abilities.forEach(z -> {
|
||||||
|
lore.add(MiniMessage.miniMessage().deserialize(
|
||||||
|
"<aqua> ⭐ <b>" + z.type.name + "</b>, " + z.type.description.replaceAll("%maxValue%", String.valueOf(z.maxValue))
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
|
|
||||||
|
meta.setEnchantmentGlintOverride(true);
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public ItemStack increaseEXP(ItemStack item, int amount) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return item;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
int exp = pdc.get(ToolUtils.EXPERIENCE, PersistentDataType.INTEGER) + amount;
|
||||||
|
int total = pdc.get(ToolUtils.TOTAL_EXPERIENCE, PersistentDataType.INTEGER) + amount;
|
||||||
|
|
||||||
|
pdc.set(ToolUtils.EXPERIENCE, PersistentDataType.INTEGER, exp);
|
||||||
|
pdc.set(ToolUtils.TOTAL_EXPERIENCE, PersistentDataType.INTEGER, total);
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return this.renderItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component name() {
|
||||||
|
return MiniMessage.miniMessage().deserialize(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------ */
|
||||||
|
/* Builder API (shared) */
|
||||||
|
/* ------------------------------------------------ */
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T addEnchantment(ToolUtils.EnchantmentType type, int amount) {
|
||||||
|
definedEnchantments.add(new ToolUtils.Enchantment(type, amount));
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T limit(ToolUtils.EnchantmentType type, int max) {
|
||||||
|
definedEnchantLimits.put(type, max);
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T addAbility(ToolUtils.AbilityType type, double max, int unlock, double cost, boolean byDefault) {
|
||||||
|
definedAbilities.add(new ToolUtils.Ability(type, max, unlock, cost, byDefault));
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
}
|
||||||
267
src/main/java/ovh/sad/snowcore/items/ToolUtils.java
Normal file
267
src/main/java/ovh/sad/snowcore/items/ToolUtils.java
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
package ovh.sad.snowcore.items;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.persistence.PersistentDataAdapterContext;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ToolUtils {
|
||||||
|
static final NamespacedKey ABILITIES = new NamespacedKey(Snowcore.PLUGIN, "snowcore_abilities");
|
||||||
|
static final NamespacedKey ENCHANTMENTS = new NamespacedKey(Snowcore.PLUGIN, "snowcore_enchants");
|
||||||
|
static final NamespacedKey EXPERIENCE = new NamespacedKey(Snowcore.PLUGIN, "snowcore_exp");
|
||||||
|
static final NamespacedKey TOTAL_EXPERIENCE = new NamespacedKey(Snowcore.PLUGIN, "snowcore_exp_total");
|
||||||
|
|
||||||
|
public enum EnchantmentType {
|
||||||
|
|
||||||
|
FORTUNE("Fortune", 200, true),
|
||||||
|
WIND("Wind", 120, false),
|
||||||
|
DOUBLE_DROP("Double Drop", 350, false),
|
||||||
|
NONE("418 Teapot", 0, false),
|
||||||
|
|
||||||
|
SWEEPER("Sweeper", 100, false),
|
||||||
|
LAYER_REMOVER("Layer Remover", 150, false);
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final int baseExpCost;
|
||||||
|
public final boolean usesLevel; // false = chance %
|
||||||
|
|
||||||
|
EnchantmentType(String name, int baseExpCost, boolean usesLevel) {
|
||||||
|
this.baseExpCost = baseExpCost;
|
||||||
|
this.usesLevel = usesLevel;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Enchantment implements PersistentDataType<byte[], Enchantment> {
|
||||||
|
public static final Enchantment EMPTY_INSTANCE = new Enchantment(EnchantmentType.NONE, 0);
|
||||||
|
|
||||||
|
public final EnchantmentType type;
|
||||||
|
public int amount;
|
||||||
|
|
||||||
|
public Enchantment(EnchantmentType type, int amount) {
|
||||||
|
this.type = type;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExpRequired(int level) {
|
||||||
|
if(type.usesLevel) {
|
||||||
|
return type.baseExpCost * level * level;
|
||||||
|
} else {
|
||||||
|
double l = level / 10.0;
|
||||||
|
return (int)Math.ceil(type.baseExpCost * Math.pow(l, 1.7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enchantment copy() {
|
||||||
|
return new Enchantment(type, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Class<byte[]> getPrimitiveType() {
|
||||||
|
return byte[].class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Class<Enchantment> getComplexType() {
|
||||||
|
return Enchantment.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte @NotNull [] toPrimitive(Enchantment complex, @NotNull PersistentDataAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(
|
||||||
|
Integer.BYTES + // enum ordinal
|
||||||
|
Integer.BYTES // amount
|
||||||
|
);
|
||||||
|
|
||||||
|
bb.putInt(complex.type.ordinal());
|
||||||
|
bb.putInt(complex.amount);
|
||||||
|
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Enchantment fromPrimitive(byte @NotNull [] primitive, @NotNull PersistentDataAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(primitive);
|
||||||
|
|
||||||
|
EnchantmentType type = EnchantmentType.values()[bb.getInt()];
|
||||||
|
int amount = bb.getInt();
|
||||||
|
|
||||||
|
return new Enchantment(type, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum AbilityType {
|
||||||
|
// Hoe only
|
||||||
|
JACKPOT("Jackpot", "you have a %maxValue%% chance to drop 5x items!"),
|
||||||
|
THREE_BY_THREE("3x3", "you mine blocks in a 3x3 grid!"),
|
||||||
|
|
||||||
|
// Shovel only
|
||||||
|
NUKE("Nuke", "you have a 10% chance to remove 108 layers of snow in a 6x6 area!"),
|
||||||
|
WIFI("Free wifi anywhere you go", "you have a %maxValue%% chance of getting a inventory full of snowballs!"),
|
||||||
|
|
||||||
|
// Mutual
|
||||||
|
MULTIPLIER("Multiplier", "your drops are multiplied by %maxValue%x!"),
|
||||||
|
AUTOSELL("Auto-sell", "you automatically sell all of your items when your inventory is full"),
|
||||||
|
|
||||||
|
NONE("HTTP", "418 Teapot");
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final String description;
|
||||||
|
|
||||||
|
AbilityType(String name, String description) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ability implements PersistentDataType<byte[], Ability> {
|
||||||
|
public static final Ability EMPTY_INSTANCE = new Ability(AbilityType.NONE, 0, 0, 0, false);
|
||||||
|
|
||||||
|
public AbilityType type;
|
||||||
|
|
||||||
|
public double maxValue;
|
||||||
|
public int unlockLevel;
|
||||||
|
public double baseCost;
|
||||||
|
|
||||||
|
public boolean byDefault;
|
||||||
|
|
||||||
|
public Ability(AbilityType type, double maxValue, int unlockLevel, double baseCost, boolean byDefault) {
|
||||||
|
this.type = type;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
this.unlockLevel = unlockLevel;
|
||||||
|
this.baseCost = baseCost;
|
||||||
|
this.byDefault = byDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Class<byte[]> getPrimitiveType() {
|
||||||
|
return byte[].class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Class<Ability> getComplexType() {
|
||||||
|
return Ability.class;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte @NotNull [] toPrimitive(Ability complex, @NotNull PersistentDataAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(
|
||||||
|
Integer.BYTES + // enum ordinal
|
||||||
|
Double.BYTES + // maxValue
|
||||||
|
Integer.BYTES + // unlockLevel
|
||||||
|
Double.BYTES + // baseCost
|
||||||
|
Short.BYTES // byDefault
|
||||||
|
);
|
||||||
|
|
||||||
|
bb.putInt(complex.type.ordinal());
|
||||||
|
bb.putDouble(complex.maxValue);
|
||||||
|
bb.putInt(complex.unlockLevel);
|
||||||
|
bb.putDouble(complex.baseCost);
|
||||||
|
|
||||||
|
if(complex.byDefault) {
|
||||||
|
bb.putShort((short)1);
|
||||||
|
} else {
|
||||||
|
bb.putShort((short)0);
|
||||||
|
}
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Ability fromPrimitive(byte @NotNull [] primitive, @NotNull PersistentDataAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(primitive);
|
||||||
|
|
||||||
|
AbilityType type = AbilityType.values()[bb.getInt()];
|
||||||
|
double maxValue = bb.getDouble();
|
||||||
|
int unlockLevel = bb.getInt();
|
||||||
|
double baseCost = bb.getDouble();
|
||||||
|
boolean byDefault = bb.getShort() == 1;
|
||||||
|
|
||||||
|
return new Ability(type, maxValue, unlockLevel, baseCost, byDefault);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable Integer getLevel(@NotNull ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return null;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
return Snowcore.getLevelFromExp(pdc.get(ToolUtils.TOTAL_EXPERIENCE, PersistentDataType.INTEGER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable Integer getExp(@NotNull ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return null;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
return pdc.get(ToolUtils.EXPERIENCE, PersistentDataType.INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable ItemStack setExp(Tool<?> tool, @NotNull ItemStack item, Integer exp) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return null;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
pdc.set(ToolUtils.EXPERIENCE, PersistentDataType.INTEGER, exp);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
|
||||||
|
return tool.renderItem(item);
|
||||||
|
}
|
||||||
|
public static @Nullable List<Enchantment> getEnchantments(@NotNull ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return null;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
return pdc.get(ToolUtils.ENCHANTMENTS, PersistentDataType.LIST.listTypeFrom(ToolUtils.Enchantment.EMPTY_INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull ItemStack setEnchantments(Tool<?> tool, @NotNull ItemStack item, @NotNull List<ToolUtils.Enchantment> enchantments) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return item;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
pdc.set(ToolUtils.ENCHANTMENTS,
|
||||||
|
PersistentDataType.LIST.listTypeFrom(ToolUtils.Enchantment.EMPTY_INSTANCE),
|
||||||
|
enchantments);
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return tool.renderItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable List<ToolUtils.Ability> getAbilities(@NotNull ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return null;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
|
||||||
|
return pdc.get(ToolUtils.ABILITIES, PersistentDataType.LIST.listTypeFrom(ToolUtils.Ability.EMPTY_INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull ItemStack setAbilities(Tool<?> tool, @NotNull ItemStack item, @NotNull List<ToolUtils.Ability> abilities) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta == null) return item;
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = meta.getPersistentDataContainer();
|
||||||
|
pdc.set(ToolUtils.ABILITIES,
|
||||||
|
PersistentDataType.LIST.listTypeFrom(ToolUtils.Ability.EMPTY_INSTANCE),
|
||||||
|
abilities);
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return tool.renderItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
400
src/main/java/ovh/sad/snowcore/listeners/BreakListener.java
Normal file
400
src/main/java/ovh/sad/snowcore/listeners/BreakListener.java
Normal file
|
|
@ -0,0 +1,400 @@
|
||||||
|
package ovh.sad.snowcore.listeners;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.Style;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.title.Title;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.type.Snow;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import ovh.sad.snowcore.items.ToolUtils;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
|
||||||
|
|
||||||
|
public class BreakListener implements Listener {
|
||||||
|
@EventHandler
|
||||||
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
// Creative mode can break anything
|
||||||
|
if (player.getGameMode() == GameMode.CREATIVE) return;
|
||||||
|
|
||||||
|
PlayerInventory inv = player.getInventory();
|
||||||
|
ItemStack hand = inv.getItemInMainHand();
|
||||||
|
Material tool = hand.getType();
|
||||||
|
Material blockType = event.getBlock().getType();
|
||||||
|
|
||||||
|
Hoe hoe = Hoe.HoeDefinitions.ALL_HOES.get(tool);
|
||||||
|
|
||||||
|
// If block has a required hoe and player doesn't meet it
|
||||||
|
if (hoe != null && !Hoe.HoeDefinitions.getAllBlocks(hoe).contains(blockType)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
Snowcore.sendActionBar(player,
|
||||||
|
Component.text("You need at least a ")
|
||||||
|
.append(Objects.requireNonNull(Hoe.HoeDefinitions.getRequiredHoe(blockType)).name())
|
||||||
|
.append(Component.text(" to break this block!"))
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hoe != null) {
|
||||||
|
event.setDropItems(false);
|
||||||
|
List<ToolUtils.Ability> abilities = ToolUtils.getAbilities(hand);
|
||||||
|
List<ToolUtils.Enchantment> enchants = ToolUtils.getEnchantments(hand);
|
||||||
|
|
||||||
|
int multiplier = 1;
|
||||||
|
|
||||||
|
Optional<ToolUtils.Ability> hasMultiplier
|
||||||
|
= abilities.stream().filter(z -> z.type == ToolUtils.AbilityType.MULTIPLIER).findFirst();
|
||||||
|
Optional<ToolUtils.Ability> hasJackpot
|
||||||
|
= abilities.stream().filter(z -> z.type == ToolUtils.AbilityType.JACKPOT).findFirst();
|
||||||
|
Optional<ToolUtils.Enchantment> windEnchantment
|
||||||
|
= enchants.stream().filter(z -> z.type == ToolUtils.EnchantmentType.WIND).findFirst();
|
||||||
|
Optional<ToolUtils.Enchantment> doubleDropEnchantment
|
||||||
|
= enchants.stream().filter(z -> z.type == ToolUtils.EnchantmentType.DOUBLE_DROP).findFirst();
|
||||||
|
|
||||||
|
if(hasMultiplier.isPresent()) {
|
||||||
|
multiplier = (int)Math.ceil(hasMultiplier.get().maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean jackpotHit = false;
|
||||||
|
double random = Math.random(); // 0.0 - 1.0
|
||||||
|
|
||||||
|
if (hasJackpot.isPresent()) {
|
||||||
|
if (random <= (hasJackpot.get().maxValue / 100)) { // 10% chance
|
||||||
|
multiplier *= 5;
|
||||||
|
jackpotHit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jackpotHit) {
|
||||||
|
player.sendActionBar(MiniMessage.miniMessage().deserialize("<yellow> ࿏࿏࿏࿏ <white> Jackpot! You got 5x drops!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<ItemStack> drops = new ArrayList<>();
|
||||||
|
List<Material> breakableBlocks = Hoe.HoeDefinitions.getAllBlocks(hoe);
|
||||||
|
List<Block> blocksToBreak = new ArrayList<>();
|
||||||
|
blocksToBreak.add(event.getBlock());
|
||||||
|
|
||||||
|
if (abilities.stream().anyMatch(z -> z.type == ToolUtils.AbilityType.THREE_BY_THREE)) {
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
|
if (dx == 0 && dz == 0) continue; // skip center (already added)
|
||||||
|
Block b = event.getBlock().getWorld().getBlockAt(
|
||||||
|
event.getBlock().getX() + dx,
|
||||||
|
event.getBlock().getY(),
|
||||||
|
event.getBlock().getZ() + dz
|
||||||
|
);
|
||||||
|
if (breakableBlocks.contains(b.getType())) {
|
||||||
|
blocksToBreak.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(windEnchantment.isPresent() && Math.random() <= (double) windEnchantment.get().amount / 100.0) {
|
||||||
|
org.bukkit.util.Vector randomDir = new org.bukkit.util.Vector(
|
||||||
|
(Math.random() * 2.0) - 1.0,
|
||||||
|
0,
|
||||||
|
(Math.random() * 2.0) - 1.0
|
||||||
|
).normalize();
|
||||||
|
|
||||||
|
World world = event.getBlock().getWorld();
|
||||||
|
Block origin = event.getBlock();
|
||||||
|
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
org.bukkit.util.Vector offset = randomDir.clone().multiply(i);
|
||||||
|
|
||||||
|
Block b = world.getBlockAt(
|
||||||
|
origin.getX() + offset.getBlockX(),
|
||||||
|
origin.getY(),
|
||||||
|
origin.getZ() + offset.getBlockZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (breakableBlocks.contains(b.getType())) {
|
||||||
|
blocksToBreak.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//org.bukkit.util.Vector velocityBoost = randomDir.clone().multiply(0.2);
|
||||||
|
//velocityBoost.setY(0.1);
|
||||||
|
//player.setVelocity(player.getVelocity().add(velocityBoost));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Block b : blocksToBreak) {
|
||||||
|
Collection<ItemStack> dropsForThisBlock = b.getDrops(hand);
|
||||||
|
|
||||||
|
if(dropsForThisBlock.isEmpty()) {
|
||||||
|
drops.add(new ItemStack(b.getType(), 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
drops.addAll(dropsForThisBlock);
|
||||||
|
|
||||||
|
b.setType(Material.AIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ToolUtils.Ability> hasAutosell
|
||||||
|
= abilities.stream().filter(z -> z.type == ToolUtils.AbilityType.AUTOSELL).findFirst();
|
||||||
|
Optional<ToolUtils.Enchantment> fortuneLevel = enchants.stream().filter(z -> z.type == ToolUtils.EnchantmentType.FORTUNE).findFirst();
|
||||||
|
|
||||||
|
int exp = 0;
|
||||||
|
|
||||||
|
for (ItemStack drop : drops) {
|
||||||
|
int amount = drop.getAmount();
|
||||||
|
|
||||||
|
if(fortuneLevel.isPresent()) {
|
||||||
|
amount = Snowcore.fortuneToDrops(fortuneLevel.get().amount, drop.getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(doubleDropEnchantment.isPresent() && Math.random() <= (double) doubleDropEnchantment.get().amount / 100.0) {
|
||||||
|
drop.setAmount((int) Math.ceil(Math.pow(amount * multiplier, 2)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
drop.setAmount(amount * multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
exp += amount * multiplier;
|
||||||
|
|
||||||
|
HashMap<Integer, ItemStack> leftover = inv.addItem(drop);
|
||||||
|
if(!leftover.isEmpty()) {
|
||||||
|
if(hasAutosell.isPresent()) {
|
||||||
|
Snowcore.sellInventory(player);
|
||||||
|
} else {
|
||||||
|
fullInventory(player);
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ItemStack stack = hoe.increaseEXP(hand, exp);
|
||||||
|
|
||||||
|
inv.setItemInMainHand(stack);
|
||||||
|
|
||||||
|
player.incrementStatistic(Statistic.MINE_BLOCK, Material.BEDROCK, breakableBlocks.size()); // bedrock because i'd like to group all flowers up into a single statistic. this works well enough!
|
||||||
|
event.getBlock().setType(Material.AIR);
|
||||||
|
} else {
|
||||||
|
if(Tag.ITEMS_SHOVELS.isTagged(tool) && blockType.equals(Material.SNOW)) {
|
||||||
|
event.setDropItems(false);
|
||||||
|
Snow snowData = (Snow) event.getBlock().getBlockData();
|
||||||
|
Shovel shovel = Shovel.ShovelDefinitions.ALL_SHOVELS.get(tool);
|
||||||
|
|
||||||
|
List<ToolUtils.Ability> abilities = ToolUtils.getAbilities(hand);
|
||||||
|
List<ToolUtils.Enchantment> enchants = ToolUtils.getEnchantments(hand);
|
||||||
|
|
||||||
|
int amountOfSnow = snowData.getLayers();
|
||||||
|
|
||||||
|
Block origin = event.getBlock();
|
||||||
|
var world = origin.getWorld();
|
||||||
|
|
||||||
|
ToolUtils.Ability nukeAbility = abilities.stream()
|
||||||
|
.filter(a -> a.type == ToolUtils.AbilityType.NUKE)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
ToolUtils.Enchantment sweepEnchantment = enchants.stream()
|
||||||
|
.filter(a -> a.type == ToolUtils.EnchantmentType.SWEEPER)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
ToolUtils.Enchantment layerRemoverEnchantment = enchants.stream()
|
||||||
|
.filter(a -> a.type == ToolUtils.EnchantmentType.LAYER_REMOVER)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
ToolUtils.Ability multiplierAbility = abilities.stream()
|
||||||
|
.filter(a -> a.type == ToolUtils.AbilityType.MULTIPLIER)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
boolean hasNuke = nukeAbility != null;
|
||||||
|
double chance = hasNuke ? nukeAbility.maxValue : 0.0;
|
||||||
|
|
||||||
|
boolean triggerNuke = hasNuke && Math.random() <= chance / 100.0;
|
||||||
|
|
||||||
|
List<Pair<Block, Integer>> targets = new ArrayList<>();
|
||||||
|
|
||||||
|
targets.add(Pair.of(event.getBlock(), amountOfSnow));
|
||||||
|
|
||||||
|
if (sweepEnchantment != null &&
|
||||||
|
Math.random() <= (double) sweepEnchantment.amount / 100.0) {
|
||||||
|
|
||||||
|
// player horizontal facing
|
||||||
|
org.bukkit.util.Vector forward = player.getLocation().getDirection().setY(0).normalize();
|
||||||
|
|
||||||
|
// perpendicular sideways vector
|
||||||
|
org.bukkit.util.Vector side = new org.bukkit.util.Vector(-forward.getZ(), 0, forward.getX());
|
||||||
|
|
||||||
|
for (int depth = 1; depth <= 2; depth++) {
|
||||||
|
for (int width = -1; width <= 1; width++) {
|
||||||
|
|
||||||
|
org.bukkit.util.Vector offset = forward.clone().multiply(depth)
|
||||||
|
.add(side.clone().multiply(width));
|
||||||
|
|
||||||
|
Block b = origin.getRelative(
|
||||||
|
offset.getBlockX(),
|
||||||
|
0,
|
||||||
|
offset.getBlockZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (b.getType() == Material.SNOW) {
|
||||||
|
Snow snow = (Snow) b.getBlockData();
|
||||||
|
int snowToRemove = Math.min(2, snow.getLayers());
|
||||||
|
amountOfSnow += snowToRemove;
|
||||||
|
targets.add(Pair.of(b, snowToRemove));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(layerRemoverEnchantment != null && Math.random() <= (double) layerRemoverEnchantment.amount / 100.0) {
|
||||||
|
org.bukkit.util.Vector forward = player.getLocation().getDirection().setY(0).normalize();
|
||||||
|
org.bukkit.util.Vector side = new org.bukkit.util.Vector(-forward.getZ(), 0, forward.getX());
|
||||||
|
|
||||||
|
for (int depth = 1; depth <= 6; depth++) {
|
||||||
|
org.bukkit.util.Vector forwardOffset = forward.clone().multiply(depth);
|
||||||
|
|
||||||
|
Block center = origin.getRelative(
|
||||||
|
forwardOffset.getBlockX(),
|
||||||
|
0,
|
||||||
|
forwardOffset.getBlockZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (center.getType() == Material.SNOW) {
|
||||||
|
Snow snow = (Snow) center.getBlockData();
|
||||||
|
int layers = snow.getLayers();
|
||||||
|
amountOfSnow += layers;
|
||||||
|
targets.add(Pair.of(center, layers));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int dir = -1; dir <= 1; dir += 2) {
|
||||||
|
org.bukkit.util.Vector sideOffset = forwardOffset.clone()
|
||||||
|
.add(side.clone().multiply(dir));
|
||||||
|
|
||||||
|
Block sideBlock = origin.getRelative(
|
||||||
|
sideOffset.getBlockX(),
|
||||||
|
0,
|
||||||
|
sideOffset.getBlockZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sideBlock.getType() == Material.SNOW) {
|
||||||
|
Snow snow = (Snow) sideBlock.getBlockData();
|
||||||
|
int snowToRemove = Math.min(
|
||||||
|
1 + (int)(Math.random() * 2),
|
||||||
|
snow.getLayers()
|
||||||
|
);
|
||||||
|
|
||||||
|
amountOfSnow += snowToRemove;
|
||||||
|
targets.add(Pair.of(sideBlock, snowToRemove));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triggerNuke) {
|
||||||
|
for (int dx = -6; dx <= 6; dx++) {
|
||||||
|
for (int dz = -6; dz <= 6; dz++) {
|
||||||
|
|
||||||
|
if (dx == 0 && dz == 0) continue;
|
||||||
|
|
||||||
|
Block b = world.getBlockAt(
|
||||||
|
origin.getX() + dx,
|
||||||
|
origin.getY(),
|
||||||
|
origin.getZ() + dz
|
||||||
|
);
|
||||||
|
|
||||||
|
if (b.getType() != Material.SNOW) continue;
|
||||||
|
|
||||||
|
Snow snow = (Snow) b.getBlockData();
|
||||||
|
int snowToRemove = Math.min(3, snow.getLayers());
|
||||||
|
|
||||||
|
amountOfSnow += snowToRemove;
|
||||||
|
targets.add(Pair.of(b, snowToRemove)); // store for later destruction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ToolUtils.Enchantment> fortune = enchants.stream().filter(z-> z.type == ToolUtils.EnchantmentType.FORTUNE).findFirst();
|
||||||
|
|
||||||
|
if(fortune.isPresent()) {
|
||||||
|
amountOfSnow = Snowcore.fortuneToDrops(fortune.get().amount, amountOfSnow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(multiplierAbility != null) {
|
||||||
|
amountOfSnow += (int) Math.ceil(multiplierAbility.maxValue);
|
||||||
|
}
|
||||||
|
HashMap<Integer, ItemStack> leftover =
|
||||||
|
inv.addItem(new ItemStack(Material.SNOWBALL, amountOfSnow));
|
||||||
|
|
||||||
|
if (!leftover.isEmpty()) {
|
||||||
|
boolean hasAutosell = abilities.stream()
|
||||||
|
.anyMatch(a -> a.type == ToolUtils.AbilityType.AUTOSELL);
|
||||||
|
|
||||||
|
if (hasAutosell) {
|
||||||
|
Snowcore.sellInventory(player);
|
||||||
|
event.setCancelled(true);
|
||||||
|
return; // nothing destroyed
|
||||||
|
} else {
|
||||||
|
fullInventory(player);
|
||||||
|
event.setCancelled(true);
|
||||||
|
return; // nothing destroyed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Pair<Block, Integer> p : targets) {
|
||||||
|
Snow snow = (Snow) p.getLeft().getBlockData();
|
||||||
|
int layers = snow.getLayers();
|
||||||
|
|
||||||
|
if (layers <= p.getRight()) {
|
||||||
|
p.getLeft().setType(Material.AIR, false);
|
||||||
|
} else {
|
||||||
|
snow.setLayers(layers - p.getRight());
|
||||||
|
p.getLeft().setBlockData(snow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack stack = shovel.increaseEXP(hand, amountOfSnow);
|
||||||
|
|
||||||
|
player.getInventory().setItemInMainHand(stack);
|
||||||
|
|
||||||
|
player.incrementStatistic(Statistic.MINE_BLOCK, Material.SNOW, amountOfSnow);
|
||||||
|
event.getBlock().setType(Material.AIR);
|
||||||
|
event.setCancelled(true);
|
||||||
|
} else {
|
||||||
|
if(blockType.equals(Material.SNOW)) {
|
||||||
|
Snowcore.sendActionBar(player, Component.text("You need a shovel to break snow with!"));
|
||||||
|
} else {
|
||||||
|
Snowcore.sendActionBar(player, Component.text("You do not have permission to break this block."));
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fullInventory(Player player) {
|
||||||
|
player.showTitle(Title.title(
|
||||||
|
Component.text("⚠ ⚠ WARNING ⚠ ⚠")
|
||||||
|
.style(Style.style(TextColor.color(255, 0, 0), TextDecoration.BOLD)),
|
||||||
|
Component.text("Your inventory is full! Use /sell")
|
||||||
|
.style(Style.style(TextColor.color(255, 255, 0)))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
266
src/main/java/ovh/sad/snowcore/listeners/InteractListener.java
Normal file
266
src/main/java/ovh/sad/snowcore/listeners/InteractListener.java
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
package ovh.sad.snowcore.listeners;
|
||||||
|
|
||||||
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerArmorStandManipulateEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
import ovh.sad.snowcore.guis.UpgradeYourToolsGui;
|
||||||
|
import ovh.sad.snowcore.items.Hoe;
|
||||||
|
import dev.triumphteam.gui.guis.GuiItem;
|
||||||
|
import dev.triumphteam.gui.builder.item.ItemBuilder;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import ovh.sad.snowcore.items.ToolUtils;
|
||||||
|
import ovh.sad.snowcore.items.Shovel;
|
||||||
|
import ovh.sad.snowcore.items.Tool;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class InteractListener implements Listener {
|
||||||
|
@EventHandler
|
||||||
|
public void glass(PlayerInteractEntityEvent event) {
|
||||||
|
UUID entityUuid = event.getRightClicked().getUniqueId();
|
||||||
|
|
||||||
|
if(entityUuid.equals(UUID.fromString("96a1d63d-f9ba-490c-bee7-f5edb73a08e8"))) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
UpgradeYourToolsGui.open(event);
|
||||||
|
} else if(entityUuid.equals(UUID.fromString("237d77c8-a25f-4cd8-882e-c9da2d62ea79"))) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
event.getPlayer().sendMessage(MiniMessage.miniMessage().deserialize("<yellow> \uD83D\uDEA7\uD83D\uDEA7 Under construction!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void armorStand(PlayerArmorStandManipulateEvent pasme) {
|
||||||
|
if(pasme.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||||
|
pasme.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInteract(PlayerInteractEvent piEvent) {
|
||||||
|
|
||||||
|
Player player = piEvent.getPlayer();
|
||||||
|
ItemStack item = player.getInventory().getItemInMainHand();
|
||||||
|
|
||||||
|
if (piEvent.getClickedBlock() != null) return;
|
||||||
|
if (!player.isSneaking()) return;
|
||||||
|
|
||||||
|
Tool<?> tool = Hoe.HoeDefinitions.ALL_HOES.get(item.getType());
|
||||||
|
if(tool == null) {
|
||||||
|
tool = Shovel.ShovelDefinitions.ALL_SHOVELS.get(item.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tool == null) return;
|
||||||
|
|
||||||
|
// Create GUI
|
||||||
|
Gui gui = Gui.gui()
|
||||||
|
.title(Component.text("Upgrade your Tool"))
|
||||||
|
.rows(6)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
GuiItem filler = ItemBuilder.from(Material.BLACK_STAINED_GLASS_PANE)
|
||||||
|
.name(Component.text(" "))
|
||||||
|
.asGuiItem();
|
||||||
|
|
||||||
|
for (int row = 1; row <= 6; row++) {
|
||||||
|
for (int col = 1; col <= 9; col++) {
|
||||||
|
if (row == 1 && col == 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((row == 2 || row == 3) && (col >= 2 && col <= 8)) continue;
|
||||||
|
|
||||||
|
if ((row == 4 || row == 5) && (col >= 2 && col <= 8)) continue;
|
||||||
|
|
||||||
|
gui.setItem(row, col, filler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<ToolUtils.EnchantmentType, ToolUtils.Enchantment> ownedEnchants =
|
||||||
|
Objects.requireNonNull(ToolUtils.getEnchantments(item))
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(e -> e.type, e -> e));
|
||||||
|
|
||||||
|
Map<ToolUtils.AbilityType, ToolUtils.Ability> ownedAbilities =
|
||||||
|
Objects.requireNonNull(ToolUtils.getAbilities(item))
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(a -> a.type, a -> a));
|
||||||
|
|
||||||
|
int exp = ToolUtils.getExp(item);
|
||||||
|
int hoeLevel = ToolUtils.getLevel(item);
|
||||||
|
Iterator<ToolUtils.Enchantment> definedEnchants = tool.definedEnchantments.stream().map(ToolUtils.Enchantment::copy).iterator();
|
||||||
|
for (int row = 2; row <= 3 && definedEnchants.hasNext(); row++) {
|
||||||
|
for (int col = 2; col <= 8 && definedEnchants.hasNext(); col++) {
|
||||||
|
|
||||||
|
ToolUtils.Enchantment def = definedEnchants.next();
|
||||||
|
ToolUtils.Enchantment owned = ownedEnchants.get(def.type);
|
||||||
|
|
||||||
|
boolean has = owned != null;
|
||||||
|
int level = has ? owned.amount : 0;
|
||||||
|
int nextLevel = level + 1;
|
||||||
|
int cost = def.getExpRequired(nextLevel);
|
||||||
|
|
||||||
|
Component name;
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
Integer hasEnchantmentLimit = tool.definedEnchantLimits.get(def.type);
|
||||||
|
|
||||||
|
if(hasEnchantmentLimit != null && level >= hasEnchantmentLimit) {
|
||||||
|
name = Component.text("❌ " + def.type.name + " is at max level!", NamedTextColor.RED);
|
||||||
|
} else if (has) {
|
||||||
|
name = Component.text("✔ " + def.type.name + " Lv." + level, NamedTextColor.GREEN);
|
||||||
|
|
||||||
|
lore.add(Component.text("Click to upgrade → Lv." + nextLevel, NamedTextColor.YELLOW));
|
||||||
|
lore.add(Component.text("Cost: " + cost + " EXP", NamedTextColor.GOLD));
|
||||||
|
} else {
|
||||||
|
name = Component.text(def.type.name, NamedTextColor.YELLOW);
|
||||||
|
|
||||||
|
lore.add(Component.text("Unlock for " + cost + " EXP", NamedTextColor.GOLD));
|
||||||
|
}
|
||||||
|
|
||||||
|
Tool<?> finalTool = tool;
|
||||||
|
gui.setItem(row, col,
|
||||||
|
ItemBuilder.from(Material.ENCHANTED_BOOK)
|
||||||
|
.name(name)
|
||||||
|
.lore(lore)
|
||||||
|
.asGuiItem(ev -> {
|
||||||
|
ev.setCancelled(true);
|
||||||
|
Player whoClicked = (Player) ev.getWhoClicked();
|
||||||
|
|
||||||
|
if(level >= finalTool.definedEnchantLimits.get(def.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp >= cost) {
|
||||||
|
if(has) {
|
||||||
|
owned.amount = owned.amount + 1;
|
||||||
|
ownedEnchants.put(owned.type, owned);
|
||||||
|
} else {
|
||||||
|
ToolUtils.Enchantment copy = def.copy();
|
||||||
|
|
||||||
|
copy.amount = copy.amount + 1;
|
||||||
|
ownedEnchants.put(copy.type, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack realItem = ToolUtils.setExp(
|
||||||
|
finalTool,
|
||||||
|
ToolUtils.setEnchantments(finalTool, item, ownedEnchants.values().stream().toList()),
|
||||||
|
exp - cost
|
||||||
|
);
|
||||||
|
|
||||||
|
whoClicked.getInventory().setItemInMainHand(realItem);
|
||||||
|
whoClicked.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<green>✔ Unlocked <yellow>" + def.type.name() +
|
||||||
|
"</yellow> for <aqua>" + (int) cost + " EXP</aqua>"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
gui.close(whoClicked);
|
||||||
|
} else {
|
||||||
|
whoClicked.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red>✘ Not enough EXP! Need <aqua>" + (int) cost +
|
||||||
|
" EXP </aqua>, you have <aqua>" + (int) exp + " EXP</aqua>"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<ToolUtils.Ability> definedAbilities = tool.definedAbilities.stream().iterator();
|
||||||
|
|
||||||
|
for (int row = 4; row <= 5 && definedAbilities.hasNext(); row++) {
|
||||||
|
for (int col = 2; col <= 8 && definedAbilities.hasNext(); col++) {
|
||||||
|
|
||||||
|
ToolUtils.Ability def = definedAbilities.next();
|
||||||
|
ToolUtils.Ability owned = ownedAbilities.get(def.type);
|
||||||
|
|
||||||
|
boolean has = owned != null || def.byDefault;
|
||||||
|
boolean unlocked = hoeLevel >= def.unlockLevel;
|
||||||
|
|
||||||
|
Component name;
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
|
||||||
|
if (has) {
|
||||||
|
name = Component.text("✔ " + def.type.name, NamedTextColor.GREEN);
|
||||||
|
lore.add(Component.text("Already unlocked", NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
} else if (!unlocked) {
|
||||||
|
name = Component.text("🔒 " + def.type.name, NamedTextColor.RED);
|
||||||
|
lore.add(Component.text("Unlocks at level " + def.unlockLevel, NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
name = Component.text(def.type.name, NamedTextColor.YELLOW);
|
||||||
|
lore.add(Component.text("Cost: " + (int) def.baseCost + "$", NamedTextColor.GOLD));
|
||||||
|
lore.add(Component.text("Click to unlock", NamedTextColor.GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
Tool<?> finalTool1 = tool;
|
||||||
|
gui.setItem(row, col,
|
||||||
|
ItemBuilder.from(Material.NETHER_STAR)
|
||||||
|
.name(name)
|
||||||
|
.lore(lore)
|
||||||
|
.asGuiItem(ev -> {
|
||||||
|
ev.setCancelled(true);
|
||||||
|
Player whoClicked = (Player) ev.getWhoClicked();
|
||||||
|
|
||||||
|
if(def.unlockLevel > hoeLevel) {
|
||||||
|
whoClicked.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red>✘ Your level is not high enough. Required level is " + def.unlockLevel
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
double cost = def.baseCost;
|
||||||
|
double balance = Snowcore.econ.getBalance(whoClicked);
|
||||||
|
|
||||||
|
if (balance >= cost) {
|
||||||
|
Snowcore.econ.withdrawPlayer(whoClicked, cost);
|
||||||
|
|
||||||
|
ownedAbilities.put(def.type, def);
|
||||||
|
ItemStack realItem =
|
||||||
|
ToolUtils.setAbilities(finalTool1, item, ownedAbilities.values().stream().toList());
|
||||||
|
whoClicked.getInventory().setItemInMainHand(realItem);
|
||||||
|
whoClicked.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<green>✔ Unlocked <yellow>" + def.type.name() +
|
||||||
|
"</yellow> for <gold>$" + (int) cost + "</gold>"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
gui.close(whoClicked);
|
||||||
|
} else {
|
||||||
|
whoClicked.sendMessage(
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
"<red>✘ Not enough money! Need <gold>$" + (int) cost +
|
||||||
|
"</gold>, you have <yellow>$" + (int) balance + "</yellow>"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gui.setItem(1, 5, new GuiItem(item));
|
||||||
|
|
||||||
|
gui.setDefaultClickAction(ev -> ev.setCancelled(true));
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/ovh/sad/snowcore/listeners/PlaceListener.java
Normal file
18
src/main/java/ovh/sad/snowcore/listeners/PlaceListener.java
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ovh.sad.snowcore.listeners;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import ovh.sad.snowcore.Snowcore;
|
||||||
|
|
||||||
|
public class PlaceListener implements Listener {
|
||||||
|
@EventHandler
|
||||||
|
public void onPlace(BlockPlaceEvent event) {
|
||||||
|
if(event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||||
|
Snowcore.sendActionBar(event.getPlayer(), Component.text("You cannot place blocks here!"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main/resources/plugin.yml
Normal file
8
src/main/resources/plugin.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
name: snowcore
|
||||||
|
version: '1.0-SNAPSHOT'
|
||||||
|
main: ovh.sad.snowcore.Snowcore
|
||||||
|
api-version: '1.21'
|
||||||
|
depend:
|
||||||
|
- Vault
|
||||||
|
- EconomySystem
|
||||||
|
- PlaceholderAPI
|
||||||
Loading…
Add table
Add a link
Reference in a new issue