diff --git a/.github/workflows/blob-build.yml b/.github/workflows/blob-build.yml
index ae69bea..8e74189 100644
--- a/.github/workflows/blob-build.yml
+++ b/.github/workflows/blob-build.yml
@@ -10,17 +10,28 @@ jobs:
if: startsWith(github.event.head_commit.message, '[CI skip]') == false
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: temurin
- - name: Build with Maven
- run: mvn package --file pom.xml
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Build with Gradle
+ run: ./gradlew clean shadowJar
+
+ - name: Rename jar file
+ run: mv build/libs/ExtraHeads-*.jar build/libs/ExtraHeads.jar
+
- name: Upload to Blob Builds
uses: WalshyDev/blob-builds/gh-action@main
with:
project: ExtraHeads
+ file: ./build/libs/ExtraHeads.jar
apiToken: ${{ secrets.BLOB_BUILDS_API_TOKEN }}
releaseNotes: ${{ github.event.head_commit.message }}
diff --git a/.github/workflows/maven.yml b/.github/workflows/ci.yml
similarity index 51%
rename from .github/workflows/maven.yml
rename to .github/workflows/ci.yml
index 991b086..375cb7d 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/ci.yml
@@ -1,3 +1,5 @@
+name: Java CI
+
on:
push:
branches:
@@ -11,11 +13,17 @@ jobs:
if: startsWith(github.event.head_commit.message, '[CI skip]') == false
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - name: Set up JDK 17
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: temurin
- - name: Build with Maven
- run: mvn package --file pom.xml
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Build with Gradle
+ run: ./gradlew clean shadowJar
diff --git a/.gitignore b/.gitignore
index 6a60859..0b14b1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,24 @@
-.classpath
+.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
-*.iml
-/.idea/
-/.settings/
-/bin/
-/target/
-dependency-reduced-pom.xml
\ No newline at end of file
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+.idea/
+vscode/
diff --git a/README.md b/README.md
index 1b1dd88..cfebf4b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# ExtraHeads
-ExtraHeads is a [Slimefun4](https://github.com/Slimefun/Slimefun4/) Addon.
+ExtraHeads is a [Slimefun4](https://github.com/Slimefun/Slimefun4/) Addon.
You need to install Slimefun4 in order for this plugin to work.
ExtraHeads is a Slimefun4 Addon that simply adds new mob heads to the game.
@@ -9,6 +9,9 @@ You can increase your chances by using a Sword of Beheading.
## Download ExtraHeads
You can download ExtraHeads right here: [Dev Builds](https://blob.build/project/ExtraHeads)
+### Requirements
+- Java 21+
+- Minecraft 1.18+
## Discord
You can find Slimefun's community on Discord!
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..3156542
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,58 @@
+plugins {
+ id("java")
+ id("maven-publish")
+ id("io.freefair.lombok") version "8.7.1"
+ id("com.gradleup.shadow") version "8.3.0"
+ id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
+}
+
+repositories {
+ mavenCentral()
+ maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
+ maven("https://repo.papermc.io/repository/maven-public/")
+ maven("https://jitpack.io")
+ maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
+}
+
+dependencies {
+ compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
+ compileOnly("com.github.Slimefun:Slimefun4:e02a0f61d1")
+ compileOnly("me.clip:placeholderapi:2.11.6")
+ implementation("org.bstats:bstats-bukkit:3.0.3")
+ implementation("com.google.code.findbugs:jsr305:3.0.2")
+ implementation("net.guizhanss:guizhanlib-all:2.0.0-SNAPSHOT")
+}
+
+group = "io.github.thebusybiscuit"
+version = "UNOFFICIAL"
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_21
+}
+
+publishing {
+ publications.create("maven") {
+ from(components["java"])
+ }
+}
+
+tasks.shadowJar {
+ fun doRelocate(from: String) {
+ val last = from.split(".").last()
+ relocate(from, "io.github.thebusybiscuit.extraheads.libs.$last")
+ }
+ doRelocate("org.bstats")
+ doRelocate("javax.annotation")
+ minimize()
+ archiveClassifier = ""
+}
+
+bukkit {
+ main = "io.github.thebusybiscuit.extraheads.ExtraHeads"
+ apiVersion = "1.18"
+ authors = listOf("TheBusyBiscuit", "ybw0014")
+ description = "A Slimefun Addon that adds heads of mobs"
+ website = "https://github.com/Slimefun-Addon-Community/ExtraHeads"
+ depend = listOf("Slimefun")
+ softDepend = listOf("PlaceholderAPI")
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..d64cd49
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82aa23
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1aa94a4
--- /dev/null
+++ b/gradlew
@@ -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/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# 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" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/gradlew.bat
@@ -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.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% 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
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index 7d16db0..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
- 4.0.0
- io.github.thebusybiscuit
- ExtraHeads
- UNOFFICIAL
-
-
- 16
- 16
- UTF-8
-
-
-
-
- paper-repo
- https://repo.destroystokyo.com/repository/maven-public/
-
-
- spigot-repo
- https://hub.spigotmc.org/nexus/content/repositories/snapshots/
-
-
- jitpack.io
- https://jitpack.io
-
-
- bstats-repo
- https://repo.codemc.org/repository/maven-public
-
-
-
-
- ${project.name} v${project.version}
- clean package
- ${basedir}/src/main/java
-
-
-
- ${basedir}/src/main/resources
- true
-
- *
-
-
-
- ${basedir}
-
-
- LICENSE
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.5.0
-
-
- true
-
-
-
-
- org.bstats
- io.github.thebusybiscuit.extraheads.bstats
-
-
-
-
-
-
- *:*
-
- META-INF/*
-
-
-
-
-
-
-
- package
-
- shade
-
-
-
-
-
-
-
-
-
- org.spigotmc
- spigot-api
- 1.20.1-R0.1-SNAPSHOT
- provided
-
-
-
- com.github.slimefun
- Slimefun4
- RC-36
- provided
-
-
- io.github.baked-libs
- dough-api
-
-
-
-
-
- org.bstats
- bstats-bukkit
- 3.0.2
- compile
-
-
-
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..790f71e
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1 @@
+rootProject.name = "ExtraHeads"
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/ExtraHeads.java b/src/main/java/io/github/thebusybiscuit/extraheads/ExtraHeads.java
index 66e4160..cebc1ce 100644
--- a/src/main/java/io/github/thebusybiscuit/extraheads/ExtraHeads.java
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/ExtraHeads.java
@@ -1,177 +1,57 @@
package io.github.thebusybiscuit.extraheads;
-import java.util.EnumMap;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import javax.annotation.Nonnull;
import org.bstats.bukkit.Metrics;
-import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
-import org.bukkit.entity.EntityType;
-import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
-import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
+import io.github.thebusybiscuit.extraheads.listeners.HeadListener;
+import io.github.thebusybiscuit.extraheads.setup.ItemSetup;
+import io.github.thebusybiscuit.extraheads.setup.Registry;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
-import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
-import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
-import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.libraries.dough.config.Config;
-import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack;
import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.BlobBuildUpdater;
-import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
-import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
+
+import lombok.Getter;
public class ExtraHeads extends JavaPlugin implements SlimefunAddon {
- private final Map mobs = new EnumMap<>(EntityType.class);
+ @Getter
+ private static ExtraHeads instance;
- private Config cfg;
- private Logger logger;
+ private Registry registry;
- private ItemGroup itemGroup;
- private RecipeType recipeType;
+ public static Registry getRegistry() {
+ return getInstance().registry;
+ }
@Override
public void onEnable() {
- cfg = new Config(this);
- logger = getLogger();
+ instance = this;
+
+ // registry and config
+ registry = new Registry(new Config(this));
// Setting up bStats
new Metrics(this, 5650);
- if (cfg.getBoolean("options.auto-update") && getDescription().getVersion().startsWith("Dev")) {
+ if (registry.getConfig().getBoolean("options.auto-update") && getPluginVersion().startsWith("Dev")) {
new BlobBuildUpdater(this, getFile(), "ExtraHeads").start();
}
- itemGroup = new ItemGroup(
- new NamespacedKey(this, "heads"),
- new CustomItemStack(
- SlimefunUtils.getCustomHead("5f1379a82290d7abe1efaabbc70710ff2ec02dd34ade386bc00c930c461cf932"),
- "&7Extra Heads"
- ),
- 1
- );
- recipeType = new RecipeType(
- new NamespacedKey(this, "decapitation"),
- new CustomItemStack(
- Material.IRON_SWORD,
- "&6Kill the specified Mob"
- )
- );
-
- registerHead(EntityType.BAT, "2796aa6d18edc5b724bd89e983bc3215a41bf775d112635e9b5835d1b8ad20cb");
- registerHead(EntityType.BLAZE, "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0");
- registerHead(EntityType.CAVE_SPIDER, "41645dfd77d09923107b3496e94eeb5c30329f97efc96ed76e226e98224");
- registerHead(EntityType.CHICKEN, "1638469a599ceef7207537603248a9ab11ff591fd378bea4735b346a7fae893");
- registerHead(EntityType.COW, "5d6c6eda942f7f5f71c3161c7306f4aed307d82895f9d2b07ab4525718edc5");
- registerHead(EntityType.DOLPHIN, "cefe7d803a45aa2af1993df2544a28df849a762663719bfefc58bf389ab7f5");
- registerHead(EntityType.DROWNED, "c84df79c49104b198cdad6d99fd0d0bcf1531c92d4ab6269e40b7d3cbbb8e98c");
- registerHead(EntityType.ELDER_GUARDIAN, "4adc4a6f53afa116027b51d6f2e433ee7afa5d59b2ffa04780be464fa5d61a");
- registerHead(EntityType.ENDERMAN, "7a59bb0a7a32965b3d90d8eafa899d1835f424509eadd4e6b709ada50b9cf");
- registerHead(EntityType.EVOKER, "d954135dc82213978db478778ae1213591b93d228d36dd54f1ea1da48e7cba6");
- registerHead(EntityType.GHAST, "8b6a72138d69fbbd2fea3fa251cabd87152e4f1c97e5f986bf685571db3cc0");
- registerHead(EntityType.GUARDIAN, "932c24524c82ab3b3e57c2052c533f13dd8c0beb8bdd06369bb2554da86c123");
- registerHead(EntityType.HORSE, "61902898308730c4747299cb5a5da9c25838b1d059fe46fc36896fee662729");
- registerHead(EntityType.HUSK, "d674c63c8db5f4ca628d69a3b1f8a36e29d8fd775e1a6bdb6cabb4be4db121");
- registerHead(EntityType.ILLUSIONER, "2f2882dd09723e47c0ab9663eab083d6a5969273706110c82910e61bf8a8f07e");
- registerHead(EntityType.IRON_GOLEM, "89091d79ea0f59ef7ef94d7bba6e5f17f2f7d4572c44f90f76c4819a714");
- registerHead(EntityType.LLAMA, "2a5f10e6e6232f182fe966f501f1c3799d45ae19031a1e4941b5dee0feff059b");
- registerHead(EntityType.MAGMA_CUBE, "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429");
- registerHead(EntityType.MUSHROOM_COW, "d0bc61b9757a7b83e03cd2507a2157913c2cf016e7c096a4d6cf1fe1b8db");
- registerHead(EntityType.OCELOT, "5657cd5c2989ff97570fec4ddcdc6926a68a3393250c1be1f0b114a1db1");
- registerHead(EntityType.PARROT, "a4ba8d66fecb1992e94b8687d6ab4a5320ab7594ac194a2615ed4df818edbc3");
- registerHead(EntityType.PIG, "621668ef7cb79dd9c22ce3d1f3f4cb6e2559893b6df4a469514e667c16aa4");
- registerHead(EntityType.POLAR_BEAR, "442123ac15effa1ba46462472871b88f1b09c1db467621376e2f71656d3fbc");
- registerHead(EntityType.RABBIT, "ff1559194a175935b8b4fea6614bec60bf81cf524af6f564333c555e657bc");
- registerHead(EntityType.SHEEP, "f31f9ccc6b3e32ecf13b8a11ac29cd33d18c95fc73db8a66c5d657ccb8be70");
- registerHead(EntityType.SHULKER, "b1d3534d21fe8499262de87affbeac4d25ffde35c8bdca069e61e1787ff2f");
- registerHead(EntityType.SLIME, "16ad20fc2d579be250d3db659c832da2b478a73a698b7ea10d18c9162e4d9b5");
- registerHead(EntityType.SPIDER, "cd541541daaff50896cd258bdbdd4cf80c3ba816735726078bfe393927e57f1");
- registerHead(EntityType.SQUID, "01433be242366af126da434b8735df1eb5b3cb2cede39145974e9c483607bac");
- registerHead(EntityType.STRAY, "78ddf76e555dd5c4aa8a0a5fc584520cd63d489c253de969f7f22f85a9a2d56");
- registerHead(EntityType.TURTLE, "0a4050e7aacc4539202658fdc339dd182d7e322f9fbcc4d5f99b5718a");
- registerHead(EntityType.VEX, "c2ec5a516617ff1573cd2f9d5f3969f56d5575c4ff4efefabd2a18dc7ab98cd");
- registerHead(EntityType.VILLAGER, "822d8e751c8f2fd4c8942c44bdb2f5ca4d8ae8e575ed3eb34c18a86e93b");
- registerHead(EntityType.VINDICATOR, "6deaec344ab095b48cead7527f7dee61b063ff791f76a8fa76642c8676e2173");
- registerHead(EntityType.WITCH, "ddedbee42be472e3eb791e7dbdfaf18c8fe593c638ba1396c9ef68f555cbce");
- registerHead(EntityType.WITHER, "cdf74e323ed41436965f5c57ddf2815d5332fe999e68fbb9d6cf5c8bd4139f");
- registerHead(EntityType.ZOMBIE_VILLAGER, "a6224941314bca2ebbb66b10ffd94680cc98c3435eeb71a228a08fd42c24db");
- registerHead(EntityType.RAVAGER, "1cb9f139f9489d86e410a06d8cbc670c8028137508e3e4bef612fe32edd60193");
- registerHead(EntityType.PILLAGER, "4aee6bb37cbfc92b0d86db5ada4790c64ff4468d68b84942fde04405e8ef5333");
- registerHead(EntityType.FOX, "46cff7a19e683a08e4587ea1457880313d5f341f346ceb5b0551195d810e3");
- registerHead(EntityType.PANDA, "7818b681cace1c641919f53edadecb142330d089a826b56219138c33b7a5e0db");
- registerHead(EntityType.WANDERING_TRADER, "5f1379a82290d7abe1efaabbc70710ff2ec02dd34ade386bc00c930c461cf932");
- registerHead(EntityType.PIGLIN, "11d18bbd0d795b9ac8efaad655e3d0c59fcbb9b964c2a9948ef537f4a3fbbf87");
- registerHead(EntityType.ZOMBIFIED_PIGLIN, "e935842af769380f78e8b8a88d1ea6ca2807c1e5693c2cf797456620833e936f");
- registerHead(EntityType.STRIDER, "18a9adf780ec7dd4625c9c0779052e6a15a451866623511e4c82e9655714b3c1");
-
- if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_17)) {
- registerHead(EntityType.AXOLOTL, "5c138f401c67fc2e1e387d9c90a9691772ee486e8ddbf2ed375fc8348746f936");
- registerHead(EntityType.GLOW_SQUID, "57327ee11812b764c7ade70b282cce4c58e635b2015244081d1490543da7280e");
- registerHead(EntityType.GOAT, "457a0d538fa08a7affe312903468861720f9fa34e86d44b89dcec5639265f03");
- }
-
- if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_19)) {
- // https://minecraft-heads.com/custom-heads/animals/61373-allay
- registerHead(EntityType.ALLAY, "df5de940bfe499c59ee8dac9f9c3919e7535eff3a9acb16f4842bf290f4c679f");
- // https://minecraft-heads.com/custom-heads/animals/63169-cold-frog
- registerHead(EntityType.FROG, "45852a95928897746012988fbd5dbaa1b70b7a5fb65157016f4ff3f245374c08");
- // https://minecraft-heads.com/custom-heads/animals/51348-tadpole
- registerHead(EntityType.TADPOLE, "987035f5352334c2cba6ac4c65c2b9059739d6d0e839c1dd98d75d2e77957847");
- }
-
- if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_20)) {
- // https://minecraft-heads.com/custom-heads/animals/62878-camel
- registerHead(EntityType.CAMEL, "3642c9f71131b5df4a8c21c8c6f10684f22abafb8cd68a1d55ac4bf263a53a31");
- // https://minecraft-heads.com/custom-heads/animals/64113-sniffer
- registerHead(EntityType.SNIFFER, "fe5a8341c478a134302981e6a7758ea4ecfd8d62a0df4067897e75502f9b25de");
- }
-
- cfg.save();
+ ItemSetup.setup();
new HeadListener(this);
}
- private void registerHead(EntityType type, String texture) {
- try {
- double chance = cfg.getOrSetDefault("chances." + type.toString(), 5.0);
- SlimefunItemStack item = new SlimefunItemStack(
- type + "_HEAD",
- texture,
- "&f" + ChatUtils.humanize(type.toString()) + " Head"
- );
- new MobHead(
- itemGroup,
- item,
- recipeType,
- new CustomItemStack(
- item,
- "&rKill 1 " + ChatUtils.humanize(type.name()),
- "&7Chance: &e" + chance + "%"
- )
- ).register(this, () -> mobs.put(type, item));
- } catch (Exception x) {
- logger.log(Level.WARNING, x, () -> "Could not load Mob Head for Entity: " + type);
- }
- }
-
- public Map getMobDrops() {
- return mobs;
- }
-
- public Config getCfg() {
- return cfg;
- }
-
@Override
+ @Nonnull
public JavaPlugin getJavaPlugin() {
return this;
}
@Override
+ @Nonnull
public String getBugTrackerURL() {
return "https://github.com/Slimefun-Addon-Community/ExtraHeads/issues";
}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/HeadListener.java b/src/main/java/io/github/thebusybiscuit/extraheads/HeadListener.java
deleted file mode 100644
index da0777c..0000000
--- a/src/main/java/io/github/thebusybiscuit/extraheads/HeadListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package io.github.thebusybiscuit.extraheads;
-
-import java.util.concurrent.ThreadLocalRandom;
-
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityDeathEvent;
-
-import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
-import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
-
-public class HeadListener implements Listener {
-
- private final ExtraHeads plugin;
-
- public HeadListener(ExtraHeads plugin) {
- this.plugin = plugin;
-
- plugin.getServer().getPluginManager().registerEvents(this, plugin);
- }
-
- @EventHandler(ignoreCancelled = true)
- public void onKill(EntityDeathEvent e) {
- if (!plugin.getMobDrops().containsKey(e.getEntityType())) {
- return;
- }
-
- double chance = plugin.getCfg().getDouble("chances." + e.getEntityType());
- Player killer = e.getEntity().getKiller();
-
- if (killer != null && SlimefunUtils.isItemSimilar(killer.getInventory().getItemInMainHand(), SlimefunItems.SWORD_OF_BEHEADING, true)) {
- chance *= plugin.getCfg().getDouble("options.sword-of-beheading-multiplier");
- }
-
- if (ThreadLocalRandom.current().nextInt(100) < chance) {
- e.getEntity().getWorld().dropItemNaturally(e.getEntity().getLocation(), plugin.getMobDrops().get(e.getEntityType()));
- }
- }
-
-}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/MobHead.java b/src/main/java/io/github/thebusybiscuit/extraheads/MobHead.java
deleted file mode 100644
index d97c5fe..0000000
--- a/src/main/java/io/github/thebusybiscuit/extraheads/MobHead.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.github.thebusybiscuit.extraheads;
-
-import org.bukkit.inventory.ItemStack;
-
-import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
-import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
-import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
-import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-
-public class MobHead extends SlimefunItem {
-
- private Runnable runnable;
-
- public MobHead(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack recipe) {
- super(itemGroup, item, recipeType, new ItemStack[] { null, null, null, null, recipe, null, null, null, null });
- }
-
- public void register(ExtraHeads plugin, Runnable runnable) {
- this.runnable = runnable;
- register(plugin);
- }
-
- @Override
- public void postRegister() {
- super.postRegister();
-
- if (!isDisabled()) {
- runnable.run();
- }
- }
-
-}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/items/MobHead.java b/src/main/java/io/github/thebusybiscuit/extraheads/items/MobHead.java
new file mode 100644
index 0000000..e7acc44
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/items/MobHead.java
@@ -0,0 +1,38 @@
+package io.github.thebusybiscuit.extraheads.items;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.extraheads.ExtraHeads;
+import io.github.thebusybiscuit.extraheads.setup.ItemGroups;
+import io.github.thebusybiscuit.extraheads.setup.RecipeTypes;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
+
+import lombok.Getter;
+
+public class MobHead extends SlimefunItem {
+
+ @Getter
+ private final EntityType entityType;
+
+ @ParametersAreNonnullByDefault
+ public MobHead(EntityType type, SlimefunItemStack item, ItemStack recipe) {
+ super(ItemGroups.MAIN, item, RecipeTypes.DECAPITATION, new ItemStack[] {
+ null, null, null, null, recipe, null, null, null, null
+ });
+
+ this.entityType = type;
+ }
+
+ @Override
+ public void postRegister() {
+ super.postRegister();
+
+ if (!isDisabled()) {
+ ExtraHeads.getRegistry().getHeads().put(entityType, this);
+ }
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/listeners/HeadListener.java b/src/main/java/io/github/thebusybiscuit/extraheads/listeners/HeadListener.java
new file mode 100644
index 0000000..57065c5
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/listeners/HeadListener.java
@@ -0,0 +1,58 @@
+package io.github.thebusybiscuit.extraheads.listeners;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.extraheads.ExtraHeads;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
+import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SwordOfBeheading;
+
+public class HeadListener implements Listener {
+
+ private final ExtraHeads plugin;
+
+ public HeadListener(ExtraHeads plugin) {
+ this.plugin = plugin;
+
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ @EventHandler(ignoreCancelled = true)
+ public void onKill(EntityDeathEvent e) {
+ var registry = ExtraHeads.getRegistry();
+ var entityType = e.getEntityType();
+ double chance = getChance(entityType, e.getEntity().getKiller());
+
+ if (ThreadLocalRandom.current().nextInt(100) < chance) {
+ e.getEntity().getWorld().dropItemNaturally(e.getEntity().getLocation(), registry.getHeads().get(entityType).getItem().clone());
+ }
+ }
+
+ private double getChance(@Nonnull EntityType type, @Nullable Player killer) {
+ if (!ExtraHeads.getRegistry().getHeads().containsKey(type)) {
+ return 0;
+ }
+ double chance = ExtraHeads.getRegistry().getConfig().getDouble("chances." + type);
+
+ if (killer == null) {
+ return chance;
+ }
+
+ ItemStack item = killer.getInventory().getItemInMainHand();
+ SwordOfBeheading sword = (SwordOfBeheading) SlimefunItems.SWORD_OF_BEHEADING.getItem();
+ if (item.isEmpty() || sword == null || !sword.isItem(item) || sword.isDisabledIn(killer.getWorld())) {
+ return chance;
+ }
+
+ return chance * ExtraHeads.getRegistry().getConfig().getDouble("options.sword-of-beheading-multiplier");
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemGroups.java b/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemGroups.java
new file mode 100644
index 0000000..4a09150
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemGroups.java
@@ -0,0 +1,20 @@
+package io.github.thebusybiscuit.extraheads.setup;
+
+import org.bukkit.NamespacedKey;
+
+import io.github.thebusybiscuit.extraheads.ExtraHeads;
+import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack;
+import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public final class ItemGroups {
+
+ public static final ItemGroup MAIN = new ItemGroup(
+ new NamespacedKey(ExtraHeads.getInstance(), "extra_heads"),
+ new CustomItemStack(SlimefunUtils.getCustomHead("5f1379a82290d7abe1efaabbc70710ff2ec02dd34ade386bc00c930c461cf932"), "&7Extra Heads"),
+ 1
+ );
+}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemSetup.java b/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemSetup.java
new file mode 100644
index 0000000..120163f
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/setup/ItemSetup.java
@@ -0,0 +1,123 @@
+package io.github.thebusybiscuit.extraheads.setup;
+
+import java.util.logging.Level;
+
+import org.bukkit.entity.EntityType;
+
+import io.github.thebusybiscuit.extraheads.ExtraHeads;
+import io.github.thebusybiscuit.extraheads.items.MobHead;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack;
+import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
+
+import net.guizhanss.guizhanlib.minecraft.utils.MinecraftVersionUtil;
+import net.guizhanss.guizhanlib.minecraft.utils.compatibility.EntityTypeX;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class ItemSetup {
+
+ public static void setup() {
+ registerHead(EntityType.BAT, "2796aa6d18edc5b724bd89e983bc3215a41bf775d112635e9b5835d1b8ad20cb");
+ registerHead(EntityType.BLAZE, "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0");
+ registerHead(EntityType.CAVE_SPIDER, "41645dfd77d09923107b3496e94eeb5c30329f97efc96ed76e226e98224");
+ registerHead(EntityType.CHICKEN, "1638469a599ceef7207537603248a9ab11ff591fd378bea4735b346a7fae893");
+ registerHead(EntityType.COW, "5d6c6eda942f7f5f71c3161c7306f4aed307d82895f9d2b07ab4525718edc5");
+ registerHead(EntityType.DOLPHIN, "cefe7d803a45aa2af1993df2544a28df849a762663719bfefc58bf389ab7f5");
+ registerHead(EntityType.DROWNED, "c84df79c49104b198cdad6d99fd0d0bcf1531c92d4ab6269e40b7d3cbbb8e98c");
+ registerHead(EntityType.ELDER_GUARDIAN, "4adc4a6f53afa116027b51d6f2e433ee7afa5d59b2ffa04780be464fa5d61a");
+ registerHead(EntityType.ENDERMAN, "7a59bb0a7a32965b3d90d8eafa899d1835f424509eadd4e6b709ada50b9cf");
+ registerHead(EntityType.EVOKER, "d954135dc82213978db478778ae1213591b93d228d36dd54f1ea1da48e7cba6");
+ registerHead(EntityType.GHAST, "8b6a72138d69fbbd2fea3fa251cabd87152e4f1c97e5f986bf685571db3cc0");
+ registerHead(EntityType.GUARDIAN, "932c24524c82ab3b3e57c2052c533f13dd8c0beb8bdd06369bb2554da86c123");
+ registerHead(EntityType.HORSE, "61902898308730c4747299cb5a5da9c25838b1d059fe46fc36896fee662729");
+ registerHead(EntityType.HUSK, "d674c63c8db5f4ca628d69a3b1f8a36e29d8fd775e1a6bdb6cabb4be4db121");
+ registerHead(EntityType.ILLUSIONER, "2f2882dd09723e47c0ab9663eab083d6a5969273706110c82910e61bf8a8f07e");
+ registerHead(EntityType.IRON_GOLEM, "89091d79ea0f59ef7ef94d7bba6e5f17f2f7d4572c44f90f76c4819a714");
+ registerHead(EntityType.LLAMA, "2a5f10e6e6232f182fe966f501f1c3799d45ae19031a1e4941b5dee0feff059b");
+ registerHead(EntityType.MAGMA_CUBE, "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429");
+ registerHead(EntityTypeX.MOOSHROOM, "d0bc61b9757a7b83e03cd2507a2157913c2cf016e7c096a4d6cf1fe1b8db");
+ registerHead(EntityType.OCELOT, "5657cd5c2989ff97570fec4ddcdc6926a68a3393250c1be1f0b114a1db1");
+ registerHead(EntityType.PARROT, "a4ba8d66fecb1992e94b8687d6ab4a5320ab7594ac194a2615ed4df818edbc3");
+ registerHead(EntityType.PIG, "621668ef7cb79dd9c22ce3d1f3f4cb6e2559893b6df4a469514e667c16aa4");
+ registerHead(EntityType.POLAR_BEAR, "442123ac15effa1ba46462472871b88f1b09c1db467621376e2f71656d3fbc");
+ registerHead(EntityType.RABBIT, "ff1559194a175935b8b4fea6614bec60bf81cf524af6f564333c555e657bc");
+ registerHead(EntityType.SHEEP, "f31f9ccc6b3e32ecf13b8a11ac29cd33d18c95fc73db8a66c5d657ccb8be70");
+ registerHead(EntityType.SHULKER, "b1d3534d21fe8499262de87affbeac4d25ffde35c8bdca069e61e1787ff2f");
+ registerHead(EntityType.SLIME, "16ad20fc2d579be250d3db659c832da2b478a73a698b7ea10d18c9162e4d9b5");
+ registerHead(EntityType.SPIDER, "cd541541daaff50896cd258bdbdd4cf80c3ba816735726078bfe393927e57f1");
+ registerHead(EntityType.SQUID, "01433be242366af126da434b8735df1eb5b3cb2cede39145974e9c483607bac");
+ registerHead(EntityType.STRAY, "78ddf76e555dd5c4aa8a0a5fc584520cd63d489c253de969f7f22f85a9a2d56");
+ registerHead(EntityType.TURTLE, "0a4050e7aacc4539202658fdc339dd182d7e322f9fbcc4d5f99b5718a");
+ registerHead(EntityType.VEX, "c2ec5a516617ff1573cd2f9d5f3969f56d5575c4ff4efefabd2a18dc7ab98cd");
+ registerHead(EntityType.VILLAGER, "822d8e751c8f2fd4c8942c44bdb2f5ca4d8ae8e575ed3eb34c18a86e93b");
+ registerHead(EntityType.VINDICATOR, "6deaec344ab095b48cead7527f7dee61b063ff791f76a8fa76642c8676e2173");
+ registerHead(EntityType.WITCH, "ddedbee42be472e3eb791e7dbdfaf18c8fe593c638ba1396c9ef68f555cbce");
+ registerHead(EntityType.WITHER, "cdf74e323ed41436965f5c57ddf2815d5332fe999e68fbb9d6cf5c8bd4139f");
+ registerHead(EntityType.ZOMBIE_VILLAGER, "a6224941314bca2ebbb66b10ffd94680cc98c3435eeb71a228a08fd42c24db");
+ registerHead(EntityType.RAVAGER, "1cb9f139f9489d86e410a06d8cbc670c8028137508e3e4bef612fe32edd60193");
+ registerHead(EntityType.PILLAGER, "4aee6bb37cbfc92b0d86db5ada4790c64ff4468d68b84942fde04405e8ef5333");
+ registerHead(EntityType.FOX, "46cff7a19e683a08e4587ea1457880313d5f341f346ceb5b0551195d810e3");
+ registerHead(EntityType.PANDA, "7818b681cace1c641919f53edadecb142330d089a826b56219138c33b7a5e0db");
+ registerHead(EntityType.WANDERING_TRADER, "5f1379a82290d7abe1efaabbc70710ff2ec02dd34ade386bc00c930c461cf932");
+ registerHead(EntityType.PIGLIN, "11d18bbd0d795b9ac8efaad655e3d0c59fcbb9b964c2a9948ef537f4a3fbbf87");
+ registerHead(EntityType.ZOMBIFIED_PIGLIN, "e935842af769380f78e8b8a88d1ea6ca2807c1e5693c2cf797456620833e936f");
+ registerHead(EntityType.STRIDER, "18a9adf780ec7dd4625c9c0779052e6a15a451866623511e4c82e9655714b3c1");
+ registerHead(EntityType.AXOLOTL, "5c138f401c67fc2e1e387d9c90a9691772ee486e8ddbf2ed375fc8348746f936");
+ registerHead(EntityType.GLOW_SQUID, "57327ee11812b764c7ade70b282cce4c58e635b2015244081d1490543da7280e");
+ registerHead(EntityType.GOAT, "457a0d538fa08a7affe312903468861720f9fa34e86d44b89dcec5639265f03");
+
+ if (MinecraftVersionUtil.isAtLeast(19)) {
+ // https://minecraft-heads.com/custom-heads/animals/61373-allay
+ registerHead(EntityType.ALLAY, "df5de940bfe499c59ee8dac9f9c3919e7535eff3a9acb16f4842bf290f4c679f");
+ // https://minecraft-heads.com/custom-heads/animals/63169-cold-frog
+ registerHead(EntityType.FROG, "45852a95928897746012988fbd5dbaa1b70b7a5fb65157016f4ff3f245374c08");
+ // https://minecraft-heads.com/custom-heads/animals/51348-tadpole
+ registerHead(EntityType.TADPOLE, "987035f5352334c2cba6ac4c65c2b9059739d6d0e839c1dd98d75d2e77957847");
+ }
+
+ if (MinecraftVersionUtil.isAtLeast(20)) {
+ // https://minecraft-heads.com/custom-heads/animals/62878-camel
+ registerHead(EntityType.CAMEL, "3642c9f71131b5df4a8c21c8c6f10684f22abafb8cd68a1d55ac4bf263a53a31");
+ // https://minecraft-heads.com/custom-heads/animals/64113-sniffer
+ registerHead(EntityType.SNIFFER, "fe5a8341c478a134302981e6a7758ea4ecfd8d62a0df4067897e75502f9b25de");
+ }
+
+ if (MinecraftVersionUtil.isAtLeast(20, 5)) {
+ // https://minecraft-heads.com/custom-heads/head/91910-armadillo
+ registerHead(EntityType.ARMADILLO, "9852b33ba294f560090752d113fe728cbc7dd042029a38d5382d65a2146068b7");
+ }
+
+ if (MinecraftVersionUtil.isAtLeast(21)) {
+ // https://minecraft-heads.com/custom-heads/head/87691-bogged
+ registerHead(EntityType.BOGGED, "a3b9003ba2d05562c75119b8a62185c67130e9282f7acbac4bc2824c21eb95d9");
+ // https://minecraft-heads.com/custom-heads/head/69108-breeze
+ registerHead(EntityType.BREEZE, "a275728af7e6a29c88125b675a39d88ae9919bb61fdc200337fed6ab0c49d65c");
+ }
+
+ ExtraHeads.getRegistry().getConfig().save();
+ }
+
+ private static void registerHead(EntityType type, String texture) {
+ try {
+ double chance = ExtraHeads.getRegistry().getConfig().getOrSetDefault("chances." + type.toString(), 5.0);
+ SlimefunItemStack item = new SlimefunItemStack(
+ type + "_HEAD",
+ texture,
+ "&f" + ChatUtils.humanize(type.toString()) + " Head"
+ );
+ new MobHead(
+ type,
+ item,
+ new CustomItemStack(
+ item,
+ "&rKill 1 " + ChatUtils.humanize(type.name()),
+ "&7Chance: &e" + chance + "%"
+ )
+ ).register(ExtraHeads.getInstance());
+ } catch (Exception x) {
+ ExtraHeads.getInstance().getLogger().log(Level.WARNING, x, () -> "Could not load Mob Head for Entity: " + type);
+ }
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/setup/RecipeTypes.java b/src/main/java/io/github/thebusybiscuit/extraheads/setup/RecipeTypes.java
new file mode 100644
index 0000000..a34ded2
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/setup/RecipeTypes.java
@@ -0,0 +1,19 @@
+package io.github.thebusybiscuit.extraheads.setup;
+
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+
+import io.github.thebusybiscuit.extraheads.ExtraHeads;
+import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class RecipeTypes {
+
+ public static final RecipeType DECAPITATION = new RecipeType(
+ new NamespacedKey(ExtraHeads.getInstance(), "decapitation"),
+ new CustomItemStack(Material.IRON_SWORD, "&6Kill the specified Mob")
+ );
+}
diff --git a/src/main/java/io/github/thebusybiscuit/extraheads/setup/Registry.java b/src/main/java/io/github/thebusybiscuit/extraheads/setup/Registry.java
new file mode 100644
index 0000000..4482972
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/extraheads/setup/Registry.java
@@ -0,0 +1,26 @@
+package io.github.thebusybiscuit.extraheads.setup;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.bukkit.entity.EntityType;
+
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.config.Config;
+
+import lombok.Getter;
+
+@Getter
+public class Registry {
+
+ private final Config config;
+ private final Map heads = new EnumMap<>(EntityType.class);
+ private final Map> entityNames = new HashMap<>();
+
+ public Registry(@Nonnull Config config) {
+ this.config = config;
+ }
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
deleted file mode 100644
index 0c82c97..0000000
--- a/src/main/resources/plugin.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: ExtraHeads
-version: ${project.version}
-author: TheBusyBiscuit
-depend: [Slimefun]
-
-main: io.github.thebusybiscuit.extraheads.ExtraHeads
-api-version: 1.16
\ No newline at end of file