diff --git a/.github/workflows/publish_to_nexus.yml b/.github/workflows/publish_to_nexus.yml
new file mode 100644
index 00000000..adc21d5a
--- /dev/null
+++ b/.github/workflows/publish_to_nexus.yml
@@ -0,0 +1,32 @@
+name: Publish to Nexus
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - dev*
+ - feature/*
+ - release/*
+
+jobs:
+ build:
+ environment: build
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2.3.4
+ - name: Set up JDK 15
+ uses: actions/setup-java@v2
+ with:
+ distribution: adopt
+ java-version: 15
+ - name: Build with Gradle
+ run: ./gradlew --build-cache build
+ - name: Test with Gradle
+ run: ./gradlew test
+ - name: Publish to eldonexus
+ run: ./gradlew publishMavenPublicationToEldoNexusRepository
+ env:
+ NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
+ NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
\ No newline at end of file
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
new file mode 100644
index 00000000..d2ff8a84
--- /dev/null
+++ b/.github/workflows/verify.yml
@@ -0,0 +1,22 @@
+name: Verify state
+
+on:
+ push:
+ pull_request:
+ types: [opened, ready_for_review, review_requested, edited]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2.3.4
+ - name: Set up JDK 15
+ uses: actions/setup-java@v2
+ with:
+ distribution: adopt
+ java-version: 15
+ - name: Build with Gradle
+ run: ./gradlew --build-cache build
+ - name: Test with Gradle
+ run: ./gradlew test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 84330c51..a4cf2c60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,65 +1,22 @@
-# Eclipse stuff
-/.classpath
-/.project
-/.settings
-
-# netbeans
-/nbproject
-
-# we use maven!
-/build.xml
-
-# maven
-/target
-
-# vim
-.*.sw[a-p]
-
-# various other potential build files
-/build
-/bin
-/dist
-/manifest.mf
-
-# Mac filesystem dust
-/.DS_Store
-
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# 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
+# Remove config
+/config/
+/logs/
+.idea/
+.gradle
+**/build/
+!src/**/build/
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
+# Ignore Gradle GUI config
+gradle-app.setting
-# 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/modules.xml
-# .idea/*.iml
-# .idea/modules
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
-# CMake
-cmake-build-*/
+# Cache of project
+.gradletasknamecache
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
+*.iml
+*.ipr
# File-based project format
*.iws
@@ -67,33 +24,17 @@ cmake-build-*/
# IntelliJ
out/
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# 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
-.idea/
-*.iml
+# CMake
+cmake-build-*/
# Maven
-log/
target/
-
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
\ No newline at end of file
diff --git a/BloodNight-api/build.gradle.kts b/BloodNight-api/build.gradle.kts
new file mode 100644
index 00000000..38ba857c
--- /dev/null
+++ b/BloodNight-api/build.gradle.kts
@@ -0,0 +1,11 @@
+plugins {
+ java
+ id("de.eldoria.library-conventions")
+}
+
+description = "BloodNight-api"
+
+java{
+ withJavadocJar()
+ withSourcesJar()
+}
\ No newline at end of file
diff --git a/BloodNight-api/pom.xml b/BloodNight-api/pom.xml
deleted file mode 100644
index 17214e52..00000000
--- a/BloodNight-api/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- BloodNight
- de.eldoria
- ${revision}
-
- 4.0.0
-
- BloodNight-api
-
-
\ No newline at end of file
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/api/IBloodNightAPI.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/api/IBloodNightAPI.java
index 6e7047c4..d554816c 100644
--- a/BloodNight-api/src/main/java/de/eldoria/bloodnight/api/IBloodNightAPI.java
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/api/IBloodNightAPI.java
@@ -8,80 +8,75 @@
* @since 0.8
*/
public interface IBloodNightAPI {
- /**
- * Checks if a blood night is active.
- *
- * @param world world
- *
- * @return true if a blood night is active.
- */
- boolean isBloodNightActive(World world);
+ /**
+ * Checks if a blood night is active.
+ *
+ * @param world world
+ * @return true if a blood night is active.
+ */
+ boolean isBloodNightActive(World world);
- /**
- * Force the next night to be a blood night in a world.
- *
- * This will not set the time in the world.
- *
- * @param world world
- */
- void forceNight(World world);
+ /**
+ * Force the next night to be a blood night in a world.
+ *
+ * This will not set the time in the world.
+ *
+ * @param world world
+ */
+ void forceNight(World world);
- /**
- * Cancels a blood night a world if one is active.
- *
- * @param world world
- */
- void cancelNight(World world);
+ /**
+ * Cancels a blood night a world if one is active.
+ *
+ * @param world world
+ */
+ void cancelNight(World world);
- /**
- * Get all worlds where a blood night is currently active.
- *
- * @return set of worlds.
- */
- Set getBloodWorlds();
+ /**
+ * Get all worlds where a blood night is currently active.
+ *
+ * @return set of worlds.
+ */
+ Set getBloodWorlds();
- /**
- * Returns how many seconds of the blood night are left.
- *
- * @param world the world to check
- *
- * @return the amount of seconds or 0 if not blood night is active.
- */
- int getSecondsLeft(World world);
+ /**
+ * Returns how many seconds of the blood night are left.
+ *
+ * @param world the world to check
+ * @return the amount of seconds or 0 if not blood night is active.
+ */
+ int getSecondsLeft(World world);
- /**
- * Get the percent of blood night duration left.
- *
- * The start is 100 and the end is 0.
- *
- * If no blood night is active this method will always return 0.
- *
- * @param world the world to check
- *
- * @return the percent between 100 and 0.
- */
- double getPercentleft(World world);
+ /**
+ * Get the percent of blood night duration left.
+ *
+ * The start is 100 and the end is 0.
+ *
+ * If no blood night is active this method will always return 0.
+ *
+ * @param world the world to check
+ * @return the percent between 100 and 0.
+ */
+ double getPercentleft(World world);
- /**
- * Get the probability of the next night to become a blood night.
- *
- * Calling this function is equal to {@link #nextProbability(World, int)} with offset 1;
- *
- * @param world world to check
- *
- * @return probability between 0 and 100. Where 100 is a guaranteed blood night.
- */
- default int nextProbability(World world) {
- return nextProbability(world, 1);
- }
+ /**
+ * Get the probability of the next night to become a blood night.
+ *
+ * Calling this function is equal to {@link #nextProbability(World, int)} with offset 1;
+ *
+ * @param world world to check
+ * @return probability between 0 and 100. Where 100 is a guaranteed blood night.
+ */
+ default int nextProbability(World world) {
+ return nextProbability(world, 1);
+ }
- /**
- * Get the probability of the next night to become a blood night.
- *
- * @param world world to check
- * @param offset offset of nights. The next night has a offset of 1. The last night has a offset of 0.
- *
- * @return probability between 0 and 100. Where 100 is a guaranteed blood night.
- */
- int nextProbability(World world, int offset);
+ /**
+ * Get the probability of the next night to become a blood night.
+ *
+ * @param world world to check
+ * @param offset offset of nights. The next night has a offset of 1. The last night has a offset of 0.
+ * @return probability between 0 and 100. Where 100 is a guaranteed blood night.
+ */
+ int nextProbability(World world, int offset);
}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigCheck.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigCheck.java
new file mode 100644
index 00000000..aed3b3e8
--- /dev/null
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigCheck.java
@@ -0,0 +1,50 @@
+package de.eldoria.bloodnight.config;
+
+public interface ConfigCheck {
+ static void isNotNull(Object object, String value) throws ConfigException {
+ if (object != null) return;
+ throw new ConfigException(value + " is not set.");
+ }
+
+ static void isNull(Object object, String value) throws ConfigException {
+ if (object == null) return;
+ throw new ConfigException(value + " is set, but shouldnt.");
+ }
+
+ static void isNotEmpty(String string, String value) throws ConfigException {
+ if (!string.trim().isEmpty()) return;
+ throw new ConfigException(value + " is empty");
+ }
+
+ /**
+ * Checks if a value is inside a range
+ *
+ * @param value value to check
+ * @param min min value (inclusive)
+ * @param max max value (inclusive)
+ * @param name name of value
+ */
+ static void isInRange(int value, int min, int max, String name) throws ConfigException {
+ if (value >= max && value >= min) return;
+ throw new ConfigException("Value " + name + " is set to " + value + ", but the defined range is " + min + " to " + max + ".");
+ }
+
+ /**
+ * Checks if a value is inside a range
+ *
+ * @param value value to check
+ * @param min min value (inclusive)
+ * @param max max value (inclusive)
+ * @param name name of value
+ */
+ static void isInRange(double value, double min, double max, String name) throws ConfigException {
+ if (value >= max && value >= min) return;
+ throw new ConfigException("Value " + name + " is set to " + value + ", but the defined range is " + min + " to " + max + ".");
+ }
+
+ default void check() throws ConfigException {
+ check(null);
+ }
+
+ void check(T data) throws ConfigException;
+}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigException.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigException.java
new file mode 100644
index 00000000..6bd11f01
--- /dev/null
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ConfigException.java
@@ -0,0 +1,7 @@
+package de.eldoria.bloodnight.config;
+
+public class ConfigException extends Exception {
+ public ConfigException(String message) {
+ super(message);
+ }
+}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ILightningSettings.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ILightningSettings.java
new file mode 100644
index 00000000..7647eac3
--- /dev/null
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/config/ILightningSettings.java
@@ -0,0 +1,13 @@
+package de.eldoria.bloodnight.config;
+
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+
+public interface ILightningSettings extends ConfigurationSerializable {
+ boolean isDoLightning();
+
+ int getLightning();
+
+ boolean isDoThunder();
+
+ int getThunder();
+}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/core/ABloodNight.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/core/ABloodNight.java
new file mode 100644
index 00000000..21db300d
--- /dev/null
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/core/ABloodNight.java
@@ -0,0 +1,10 @@
+package de.eldoria.bloodnight.core;
+
+import de.eldoria.eldoutilities.plugin.EldoPlugin;
+import org.bukkit.NamespacedKey;
+
+public class ABloodNight extends EldoPlugin {
+ public static NamespacedKey getNamespacedKey(String string) {
+ return new NamespacedKey(getInstance(), string.replace(" ", "_"));
+ }
+}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightBeginEvent.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightBeginEvent.java
index 5c538f3a..9b41415b 100644
--- a/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightBeginEvent.java
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightBeginEvent.java
@@ -15,34 +15,34 @@
@Getter
public class BloodNightBeginEvent extends WorldEvent implements Cancellable {
- private static final HandlerList HANDLERS = new HandlerList();
- private boolean cancelled;
-
- /**
- * Create a new Blood Night Begin Event.
- *
- * @param world world where the blood night has begun.
- */
- public BloodNightBeginEvent(World world) {
- super(world);
- }
-
- public static HandlerList getHandlerList() {
- return HANDLERS;
- }
-
- @Override
- public @NotNull HandlerList getHandlers() {
- return HANDLERS;
- }
-
- @Override
- public boolean isCancelled() {
- return cancelled;
- }
-
- @Override
- public void setCancelled(boolean cancelled) {
- this.cancelled = cancelled;
- }
+ private static final HandlerList HANDLERS = new HandlerList();
+ private boolean cancelled;
+
+ /**
+ * Create a new Blood Night Begin Event.
+ *
+ * @param world world where the blood night has begun.
+ */
+ public BloodNightBeginEvent(World world) {
+ super(world);
+ }
+
+ public static HandlerList getHandlerList() {
+ return HANDLERS;
+ }
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return HANDLERS;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
}
diff --git a/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightEndEvent.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightEndEvent.java
index eda15d5f..6719ce9a 100644
--- a/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightEndEvent.java
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/events/BloodNightEndEvent.java
@@ -12,23 +12,23 @@
@Getter
public class BloodNightEndEvent extends WorldEvent {
- private static final HandlerList HANDLERS = new HandlerList();
+ private static final HandlerList HANDLERS = new HandlerList();
- /**
- * Create a new Blood Night End Event.
- *
- * @param world world where the blood night has ended.
- */
- public BloodNightEndEvent(World world) {
- super(world);
- }
+ /**
+ * Create a new Blood Night End Event.
+ *
+ * @param world world where the blood night has ended.
+ */
+ public BloodNightEndEvent(World world) {
+ super(world);
+ }
- public static HandlerList getHandlerList() {
- return HANDLERS;
- }
+ public static HandlerList getHandlerList() {
+ return HANDLERS;
+ }
- @Override
- public @NotNull HandlerList getHandlers() {
- return HANDLERS;
- }
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return HANDLERS;
+ }
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/InvMenuUtil.java b/BloodNight-api/src/main/java/de/eldoria/bloodnight/utils/InvMenuUtil.java
similarity index 96%
rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/util/InvMenuUtil.java
rename to BloodNight-api/src/main/java/de/eldoria/bloodnight/utils/InvMenuUtil.java
index 087b12f5..f4f59c62 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/InvMenuUtil.java
+++ b/BloodNight-api/src/main/java/de/eldoria/bloodnight/utils/InvMenuUtil.java
@@ -1,67 +1,67 @@
-package de.eldoria.bloodnight.util;
-
-import lombok.experimental.UtilityClass;
-import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.persistence.PersistentDataContainer;
-import org.bukkit.persistence.PersistentDataType;
-
-@UtilityClass
-public class InvMenuUtil {
- private final String INV_MENU_UTIL = "inv_menu_util";
- private final NamespacedKey BOOLEAN_KEY = new NamespacedKey(INV_MENU_UTIL, "boolean");
-
- /**
- * Get a item stack with the matching material based on the state.
- *
- * This method will apply a nbt tag which marks this item as a boolean item.
- *
- * @param state current boolean state
- * @return item stack with correct material and boolean nbt tag.
- */
- public ItemStack getBooleanMaterial(boolean state) {
- Material mat = state ? Material.GREEN_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
- ItemStack itemStack = new ItemStack(mat);
-
- if (itemStack.hasItemMeta()) {
- ItemMeta itemMeta = itemStack.getItemMeta();
- PersistentDataContainer container = itemMeta.getPersistentDataContainer();
- container.set(BOOLEAN_KEY, PersistentDataType.BYTE, (byte) (state ? 1 : 0));
- itemStack.setItemMeta(itemMeta);
- }
-
- return itemStack;
- }
-
- public void toogleBoolean(ItemStack itemStack) {
- if (itemStack.hasItemMeta()) {
- ItemMeta itemMeta = itemStack.getItemMeta();
- PersistentDataContainer container = itemMeta.getPersistentDataContainer();
-
- if (container.has(BOOLEAN_KEY, PersistentDataType.BYTE)) {
- Byte aByte = container.get(BOOLEAN_KEY, PersistentDataType.BYTE);
- container.set(BOOLEAN_KEY, PersistentDataType.BYTE, (byte) (aByte == (byte) 1 ? 0 : 1));
- }
-
- itemStack.setItemMeta(itemMeta);
- }
- }
-
- public boolean getBoolean(ItemStack itemStack) {
- if (itemStack.hasItemMeta()) {
- ItemMeta itemMeta = itemStack.getItemMeta();
- PersistentDataContainer container = itemMeta.getPersistentDataContainer();
-
- if (container.has(BOOLEAN_KEY, PersistentDataType.BYTE)) {
- return container.get(BOOLEAN_KEY, PersistentDataType.BYTE) == (byte) 1;
- }
- }
- return false;
- }
-
- public Material getBooleanMat(boolean state) {
- return state ? Material.GREEN_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
- }
-}
+package de.eldoria.bloodnight.utils;
+
+import lombok.experimental.UtilityClass;
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+
+@UtilityClass
+public class InvMenuUtil {
+ private final String INV_MENU_UTIL = "inv_menu_util";
+ private final NamespacedKey BOOLEAN_KEY = new NamespacedKey(INV_MENU_UTIL, "boolean");
+
+ /**
+ * Get a item stack with the matching material based on the state.
+ *
+ * This method will apply a nbt tag which marks this item as a boolean item.
+ *
+ * @param state current boolean state
+ * @return item stack with correct material and boolean nbt tag.
+ */
+ public ItemStack getBooleanMaterial(boolean state) {
+ Material mat = state ? Material.GREEN_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
+ ItemStack itemStack = new ItemStack(mat);
+
+ if (itemStack.hasItemMeta()) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ PersistentDataContainer container = itemMeta.getPersistentDataContainer();
+ container.set(BOOLEAN_KEY, PersistentDataType.BYTE, (byte) (state ? 1 : 0));
+ itemStack.setItemMeta(itemMeta);
+ }
+
+ return itemStack;
+ }
+
+ public void toogleBoolean(ItemStack itemStack) {
+ if (itemStack.hasItemMeta()) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ PersistentDataContainer container = itemMeta.getPersistentDataContainer();
+
+ if (container.has(BOOLEAN_KEY, PersistentDataType.BYTE)) {
+ Byte aByte = container.get(BOOLEAN_KEY, PersistentDataType.BYTE);
+ container.set(BOOLEAN_KEY, PersistentDataType.BYTE, (byte) (aByte == (byte) 1 ? 0 : 1));
+ }
+
+ itemStack.setItemMeta(itemMeta);
+ }
+ }
+
+ public boolean getBoolean(ItemStack itemStack) {
+ if (itemStack.hasItemMeta()) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ PersistentDataContainer container = itemMeta.getPersistentDataContainer();
+
+ if (container.has(BOOLEAN_KEY, PersistentDataType.BYTE)) {
+ return container.get(BOOLEAN_KEY, PersistentDataType.BYTE) == (byte) 1;
+ }
+ }
+ return false;
+ }
+
+ public Material getBooleanMat(boolean state) {
+ return state ? Material.GREEN_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
+ }
+}
diff --git a/BloodNight-core/build.gradle.kts b/BloodNight-core/build.gradle.kts
new file mode 100644
index 00000000..a37baa53
--- /dev/null
+++ b/BloodNight-core/build.gradle.kts
@@ -0,0 +1,57 @@
+plugins {
+ id("com.github.johnrengelman.shadow") version "6.0.0"
+ id("de.eldoria.library-conventions")
+}
+
+dependencies {
+ api(project(":BloodNight-api"))
+ api(project(":BloodNight-mobs"))
+ implementation("net.kyori:adventure-api:4.7.0")
+ implementation("net.kyori:adventure-platform-bukkit:4.0.0-SNAPSHOT")
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.2")
+ testImplementation("org.mockito:mockito-core:3.5.13")
+ compileOnly("io.lumine.xikage:MythicMobs:4.9.1")
+ compileOnly("me.clip:placeholderapi:2.10.9")
+ compileOnly("com.onarandombox.multiversecore:Multiverse-Core:4.2.1")
+ compileOnly("se.hyperver.hyperverse:Core:0.9.0-SNAPSHOT") { isTransitive = false }
+}
+
+var mainPackage = "bloodnight"
+val shadebade = project.group as String + "." + mainPackage + "."
+val descr = "Nights are not hard enough? Make them harder!"
+
+java{
+ withSourcesJar()
+ withJavadocJar()
+}
+
+tasks {
+ processResources {
+ val publishData = PublishData(project)
+ from(sourceSets.main.get().resources.srcDirs) {
+ filesMatching("plugin.yml") {
+ expand(
+ "name" to project.parent?.name,
+ "version" to publishData.getVersion(true),
+ "description" to descr,
+ "url" to "https://www.spigotmc.org/resources/85095/"
+ )
+ }
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ }
+ }
+
+ shadowJar {
+ relocate("net.kyori", shadebade + "kyori")
+ relocate("de.eldoria.eldoutilities", shadebade + "eldoutilities")
+ mergeServiceFiles()
+ archiveBaseName.set(project.parent?.name)
+ }
+
+ test {
+ useJUnit()
+ testLogging {
+ events("passed", "skipped", "failed")
+ }
+ }
+}
\ No newline at end of file
diff --git a/BloodNight-core/pom.xml b/BloodNight-core/pom.xml
deleted file mode 100644
index 5e8a2007..00000000
--- a/BloodNight-core/pom.xml
+++ /dev/null
@@ -1,182 +0,0 @@
-
-
-
- BloodNight
- de.eldoria
- ${revision}
-
- 4.0.0
-
- BloodNight-core
-
-
- 1.8.4
- BloodNight
- Nights are not hard enough? Make them harder!
- https://www.spigotmc.org/resources/85095/
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.2.4
-
-
- false
-
-
- net.kyori
- ${shade.base}.kyori
-
-
- de.eldoria.eldoutilities
- ${shade.base}.eldoutilities
-
-
-
-
-
- package
-
- shade
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.2.0
-
- ..\..\minecraft Testserver\1.16.5\plugins
- BloodNight-${revision}
-
-
-
-
-
-
-
- EldoNexus
- https://eldonexus.de/repository/maven-releases/
-
-
- spigot-repo
- https://hub.spigotmc.org/nexus/content/repositories/snapshots/
-
-
- sonatype-oss
- https://oss.sonatype.org/content/repositories/snapshots/
-
-
- nexus
- Lumine Releases
- https://mvn.lumine.io/repository/maven-public/
-
-
- placeholderapi
- https://repo.extendedclip.com/content/repositories/placeholderapi/
-
-
- OnARandomBox
- http://repo.onarandombox.com/content/groups/public
-
-
- intellectualsites-snapshots
- https://mvn.intellectualsites.com/content/repositories/snapshots
-
-
-
-
-
- de.eldoria
- BloodNight-api
- ${revision}
-
-
- de.eldoria
- eldo-util
- ${eldoutil.version}
- compile
-
-
- net.kyori
- adventure-api
- 4.7.0
- compile
-
-
- org.checkerframework
- checker-qual
-
-
-
-
- net.kyori
- adventure-platform-bukkit
- 4.0.0-SNAPSHOT
- compile
-
-
- org.checkerframework
- checker-qual
-
-
- com.google.code.gson
- gson
-
-
-
-
-
-
- io.lumine.xikage
- MythicMobs
- 4.9.1
- provided
-
-
- me.clip
- placeholderapi
- 2.10.9
- provided
-
-
- com.onarandombox.multiversecore
- Multiverse-Core
- 4.2.1
- provided
-
-
- se.hyperver.hyperverse
- Core
- 0.9.0-SNAPSHOT
- provided
-
-
-
-
-
- org.junit.jupiter
- junit-jupiter-api
- 5.5.2
- test
-
-
- junit
- junit
- 4.13.1
- test
-
-
- org.mockito
- mockito-core
- 3.5.13
- test
-
-
-
\ No newline at end of file
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/InventoryListener.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/InventoryListener.java
index 0a66c6c9..3bd40fe1 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/InventoryListener.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/InventoryListener.java
@@ -1,47 +1,47 @@
-package de.eldoria.bloodnight.command;
-
-import de.eldoria.bloodnight.config.Configuration;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.inventory.InventoryCloseEvent;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-public class InventoryListener implements Listener {
-
- private final Map inventories = new HashMap<>();
- private final Configuration configuration;
-
- public InventoryListener(Configuration configuration) {
- this.configuration = configuration;
- }
-
- public void registerModification(Player player, InventoryActionHandler handler) {
- inventories.put(player.getUniqueId(), handler);
- }
-
- @EventHandler
- public void onInventoryClose(InventoryCloseEvent event) {
- if (inventories.containsKey(event.getPlayer().getUniqueId())) {
- inventories.remove(event.getPlayer().getUniqueId()).onInventoryClose(event);
- configuration.save();
- }
- }
-
- @EventHandler
- public void onInventoryClick(InventoryClickEvent event) {
- if (inventories.containsKey(event.getWhoClicked().getUniqueId())) {
- inventories.get(event.getWhoClicked().getUniqueId()).onInventoryClick(event);
- }
- }
-
- public interface InventoryActionHandler {
- void onInventoryClose(InventoryCloseEvent event);
-
- void onInventoryClick(InventoryClickEvent event);
- }
-}
+package de.eldoria.bloodnight.command;
+
+import de.eldoria.bloodnight.config.Configuration;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class InventoryListener implements Listener {
+
+ private final Map inventories = new HashMap<>();
+ private final Configuration configuration;
+
+ public InventoryListener(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ public void registerModification(Player player, InventoryActionHandler handler) {
+ inventories.put(player.getUniqueId(), handler);
+ }
+
+ @EventHandler
+ public void onInventoryClose(InventoryCloseEvent event) {
+ if (inventories.containsKey(event.getPlayer().getUniqueId())) {
+ inventories.remove(event.getPlayer().getUniqueId()).onInventoryClose(event);
+ configuration.save();
+ }
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ if (inventories.containsKey(event.getWhoClicked().getUniqueId())) {
+ inventories.get(event.getWhoClicked().getUniqueId()).onInventoryClick(event);
+ }
+ }
+
+ public interface InventoryActionHandler {
+ void onInventoryClose(InventoryCloseEvent event);
+
+ void onInventoryClick(InventoryClickEvent event);
+ }
+}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/CancelNight.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/CancelNight.java
index 7cd79d67..c103fc3c 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/CancelNight.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/CancelNight.java
@@ -69,7 +69,8 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command
command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ForceNight.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ForceNight.java
index 01f557fe..52342e5d 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ForceNight.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ForceNight.java
@@ -69,7 +69,8 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMob.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMob.java
index 57a5e31a..1257d509 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMob.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMob.java
@@ -4,10 +4,9 @@
import de.eldoria.bloodnight.command.util.CommandUtil;
import de.eldoria.bloodnight.config.Configuration;
import de.eldoria.bloodnight.config.worldsettings.WorldSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.Drop;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSetting;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobValueModifier;
+import de.eldoria.bloodnight.bloodmob.settings.MobValueModifier;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.core.mobfactory.MobFactory;
import de.eldoria.bloodnight.core.mobfactory.MobGroup;
@@ -27,22 +26,15 @@
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
-import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.inventory.InventoryCloseEvent;
-import org.bukkit.event.inventory.InventoryType;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
-import java.util.stream.Collectors;
public class ManageMob extends EldoCommand {
public final Configuration configuration;
@@ -222,21 +214,21 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
return true;
}
- if ("drops".equalsIgnoreCase(field)) {
+ /*if ("drops".equalsIgnoreCase(field)) {
if (!ArrayUtil.arrayContains(new String[]{"changeContent", "changeWeight", "clear"}, value)) {
messageSender().sendError(sender, localizer().getMessage("error.invalidValue"));
}
if ("changeContent".equalsIgnoreCase(value)) {
Inventory inv = Bukkit.createInventory(player, 54, localizer().getMessage("drops.dropsTitle"));
- inv.setContents(mob.getDrops().stream().map(Drop::getWeightedItem).toArray(ItemStack[]::new));
+ inv.setContents(mob.getDrops().stream().map(DropUtil::getWeightedItem).toArray(ItemStack[]::new));
player.openInventory(inv);
inventoryListener.registerModification(player, new InventoryListener.InventoryActionHandler() {
@Override
public void onInventoryClose(InventoryCloseEvent event) {
List collect = Arrays.stream(event.getInventory().getContents())
.filter(Objects::nonNull)
- .map(Drop::fromItemStack)
+ //.map(DropUtil::fromItemStack)
.collect(Collectors.toList());
mob.setDrops(collect);
optPage.ifPresent(i -> sendMobListPage(world, sender, mobGroup, i));
@@ -248,8 +240,9 @@ public void onInventoryClick(InventoryClickEvent event) {
});
}
+
if ("changeWeight".equalsIgnoreCase(value)) {
- List stacks = mob.getDrops().stream().map(Drop::getItemWithLoreWeight).collect(Collectors.toList());
+ List stacks = mob.getDrops().stream().map(DropUtil::getItemWithLoreWeight).collect(Collectors.toList());
Inventory inv = Bukkit.createInventory(player, 54, localizer().getMessage("drops.weightTitle"));
inv.setContents(stacks.toArray(new ItemStack[0]));
player.openInventory(inv);
@@ -258,7 +251,7 @@ public void onInventoryClick(InventoryClickEvent event) {
public void onInventoryClose(InventoryCloseEvent event) {
List collect = Arrays.stream(event.getInventory().getContents())
.filter(Objects::nonNull)
- .map(Drop::fromItemStack)
+ .map(DropUtil::fromItemStack)
.collect(Collectors.toList());
mob.setDrops(collect);
optPage.ifPresent(i -> sendMobListPage(world, sender, mobGroup, i));
@@ -274,16 +267,16 @@ public void onInventoryClick(InventoryClickEvent event) {
switch (event.getClick()) {
case LEFT:
- Drop.changeWeight(event.getCurrentItem(), 1);
+ DropUtil.changeWeight(event.getCurrentItem(), 1);
break;
case SHIFT_LEFT:
- Drop.changeWeight(event.getCurrentItem(), 10);
+ DropUtil.changeWeight(event.getCurrentItem(), 10);
break;
case RIGHT:
- Drop.changeWeight(event.getCurrentItem(), -1);
+ DropUtil.changeWeight(event.getCurrentItem(), -1);
break;
case SHIFT_RIGHT:
- Drop.changeWeight(event.getCurrentItem(), -10);
+ DropUtil.changeWeight(event.getCurrentItem(), -10);
break;
}
event.setCancelled(true);
@@ -291,13 +284,14 @@ public void onInventoryClick(InventoryClickEvent event) {
});
}
+
if ("clear".equalsIgnoreCase(value)) {
mob.setDrops(new ArrayList<>());
optPage.ifPresent(i -> sendMobListPage(world, sender, mobGroup, i));
configuration.save();
}
return true;
- }
+ }*/
messageSender().sendError(sender, localizer().getMessage("error.invalidField"));
return true;
@@ -422,7 +416,8 @@ private void sendMobListPage(World world, CommandSender
//group world mob field value
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command
command, @NotNull String alias, @NotNull String[] args) {
// mobgroup
if (args.length == 1) {
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMobs.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMobs.java
index 486d919d..8de39290 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMobs.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageMobs.java
@@ -4,9 +4,8 @@
import de.eldoria.bloodnight.command.util.CommandUtil;
import de.eldoria.bloodnight.config.Configuration;
import de.eldoria.bloodnight.config.worldsettings.WorldSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.Drop;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.VanillaDropMode;
+import de.eldoria.bloodnight.bloodmob.settings.VanillaDropMode;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.VanillaMobSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.util.Permissions;
@@ -23,22 +22,15 @@
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
-import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.inventory.InventoryCloseEvent;
-import org.bukkit.event.inventory.InventoryType;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
-import java.util.stream.Collectors;
public class ManageMobs extends EldoCommand {
private final BukkitAudiences bukkitAudiences = BukkitAudiences.create(BloodNight.getInstance());
@@ -165,10 +157,10 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
return true;
}
- if ("defaultDrops".equalsIgnoreCase(field)) {
+ /*if ("defaultDrops".equalsIgnoreCase(field)) {
if ("changeContent".equalsIgnoreCase(value)) {
Inventory inv = Bukkit.createInventory(player, 54, "Drops");
- List stacks = mobSettings.getDefaultDrops().stream().map(Drop::getWeightedItem).collect(Collectors.toList());
+ List stacks = mobSettings.getDefaultDrops().stream().map(DropUtil::getWeightedItem).collect(Collectors.toList());
inv.setContents(stacks.toArray(new ItemStack[0]));
player.openInventory(inv);
inventoryListener.registerModification(player, new InventoryListener.InventoryActionHandler() {
@@ -176,7 +168,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
public void onInventoryClose(InventoryCloseEvent event) {
List collect = Arrays.stream(event.getInventory().getContents())
.filter(Objects::nonNull)
- .map(Drop::fromItemStack)
+ .map(DropUtil::fromItemStack)
.collect(Collectors.toList());
mobSettings.setDefaultDrops(collect);
sendInfo(sender, worldSettings);
@@ -189,7 +181,7 @@ public void onInventoryClick(InventoryClickEvent event) {
return true;
}
if ("changeWeight".equalsIgnoreCase(value)) {
- List stacks = mobSettings.getDefaultDrops().stream().map(Drop::getItemWithLoreWeight).collect(Collectors.toList());
+ List stacks = mobSettings.getDefaultDrops().stream().map(DropUtil::getItemWithLoreWeight).collect(Collectors.toList());
Inventory inv = Bukkit.createInventory(player, 54, "Weight");
inv.setContents(stacks.toArray(new ItemStack[0]));
player.openInventory(inv);
@@ -198,7 +190,7 @@ public void onInventoryClick(InventoryClickEvent event) {
public void onInventoryClose(InventoryCloseEvent event) {
List collect = Arrays.stream(event.getInventory().getContents())
.filter(Objects::nonNull)
- .map(Drop::fromItemStack)
+ .map(DropUtil::fromItemStack)
.collect(Collectors.toList());
mobSettings.setDefaultDrops(collect);
sendInfo(sender, worldSettings);
@@ -214,16 +206,16 @@ public void onInventoryClick(InventoryClickEvent event) {
switch (event.getClick()) {
case LEFT:
- Drop.changeWeight(event.getCurrentItem(), 1);
+ DropUtil.changeWeight(event.getCurrentItem(), 1);
break;
case SHIFT_LEFT:
- Drop.changeWeight(event.getCurrentItem(), 10);
+ DropUtil.changeWeight(event.getCurrentItem(), 10);
break;
case RIGHT:
- Drop.changeWeight(event.getCurrentItem(), -1);
+ DropUtil.changeWeight(event.getCurrentItem(), -1);
break;
case SHIFT_RIGHT:
- Drop.changeWeight(event.getCurrentItem(), -10);
+ DropUtil.changeWeight(event.getCurrentItem(), -10);
break;
}
event.setCancelled(true);
@@ -239,7 +231,7 @@ public void onInventoryClick(InventoryClickEvent event) {
}
messageSender().sendError(sender, localizer().getMessage("error.invalidValue"));
return true;
- }
+ }*/
if ("vanillaDropMode".equalsIgnoreCase(field)) {
VanillaDropMode parse = EnumUtil.parse(value, VanillaDropMode.class);
@@ -371,7 +363,8 @@ private void sendInfo(CommandSender sender, WorldSettings worldSettings) {
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNight.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNight.java
index ba0308c0..ca27a84b 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNight.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNight.java
@@ -13,10 +13,10 @@
import de.eldoria.eldoutilities.utils.ArrayUtil;
import de.eldoria.eldoutilities.utils.EnumUtil;
import de.eldoria.eldoutilities.utils.Parser;
-import lombok.var;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.World;
@@ -150,7 +150,7 @@ private void sendNightSettings(CommandSender sender, WorldSettings worldSettings
NightSettings nightSettings = worldSettings.getNightSettings();
String cmd = "/bloodnight manageNight " + ArgumentUtils.escapeWorldName(worldSettings.getWorldName()) + " ";
NightSettings.NightDuration durationMode = nightSettings.getNightDurationMode();
- var builder = Component.text()
+ TextComponent.Builder builder = Component.text()
.append(Component.newline())
.append(Component.newline())
.append(Component.newline())
@@ -230,7 +230,8 @@ private void sendNightSettings(CommandSender sender, WorldSettings worldSettings
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNightSelection.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNightSelection.java
index 171a5bb6..0d91a67b 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNightSelection.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageNightSelection.java
@@ -348,7 +348,8 @@ private void sendWorldPage(World world, CommandSender sender, int p) {
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageWorlds.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageWorlds.java
index 32d5571d..dc6b26c4 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageWorlds.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/ManageWorlds.java
@@ -234,7 +234,8 @@ private void sendWorldPage(World world, CommandSender sender, int page) {
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/SpawnMob.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/SpawnMob.java
index 97364460..694bb621 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/SpawnMob.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/SpawnMob.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.command.bloodnight;
-import de.eldoria.bloodnight.core.manager.nightmanager.NightManager;
import de.eldoria.bloodnight.core.manager.mobmanager.MobManager;
+import de.eldoria.bloodnight.core.manager.nightmanager.NightManager;
import de.eldoria.bloodnight.core.mobfactory.MobFactory;
import de.eldoria.bloodnight.core.mobfactory.SpecialMobRegistry;
import de.eldoria.bloodnight.util.Permissions;
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/DeathActionUtil.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/DeathActionUtil.java
index ff688c5f..530cb952 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/DeathActionUtil.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/DeathActionUtil.java
@@ -1,9 +1,9 @@
package de.eldoria.bloodnight.command.bloodnight.managedeathactions;
import de.eldoria.bloodnight.config.Configuration;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.PotionEffectSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.LightningSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.ShockwaveSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.PotionEffectSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.LightningSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.ShockwaveSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.eldoutilities.core.EldoUtilities;
import de.eldoria.eldoutilities.inventory.ActionConsumer;
@@ -98,7 +98,7 @@ public static void buildShockwaveUI(ShockwaveSettings shockwave, Player player,
Optional optionalType = DataContainerUtil.get(stack, typeKey, PersistentDataType.STRING);
optionalType.ifPresent(name -> {
PotionEffectType type = PotionEffectType.getByName(name);
- if(integer.get() == 0){
+ if (integer.get() == 0) {
shockwave.getShockwaveEffects().remove(type);
return;
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManageMonsterDeathActions.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManageMonsterDeathActions.java
index 2999cefe..eaafb08a 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManageMonsterDeathActions.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManageMonsterDeathActions.java
@@ -73,7 +73,8 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManagePlayerDeathActions.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManagePlayerDeathActions.java
index 28116d29..4cd055f3 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManagePlayerDeathActions.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/command/bloodnight/managedeathactions/ManagePlayerDeathActions.java
@@ -3,7 +3,7 @@
import de.eldoria.bloodnight.command.util.CommandUtil;
import de.eldoria.bloodnight.config.Configuration;
import de.eldoria.bloodnight.config.worldsettings.deathactions.PlayerDeathActions;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.PotionEffectSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.PotionEffectSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.eldoutilities.conversation.ConversationRequester;
import de.eldoria.eldoutilities.core.EldoUtilities;
@@ -118,7 +118,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
Optional optionalName = DataContainerUtil.get(stack, typeKey, PersistentDataType.STRING);
optionalName.ifPresent(name -> {
PotionEffectType type = PotionEffectType.getByName(name);
- if(integer.get() == 0){
+ if (integer.get() == 0) {
respawnEffects.remove(type);
return;
}
@@ -267,7 +267,8 @@ private void sendPlayerDeathActions(Player player, World world, PlayerDeathActio
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ public @Nullable
+ List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteUtil.completeWorlds(args[0]);
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/Configuration.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/Configuration.java
index 387503fa..245e7f67 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/Configuration.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/Configuration.java
@@ -132,7 +132,8 @@ protected void saveConfigs() {
}
- private @NotNull String getWorldConfigPath(String world) {
+ private @NotNull
+ String getWorldConfigPath(String world) {
return "worldSettings/" + world;
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/generalsettings/GeneralSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/generalsettings/GeneralSettings.java
index 5582a0e9..a001cf1c 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/generalsettings/GeneralSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/generalsettings/GeneralSettings.java
@@ -12,6 +12,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
@Getter
@Setter
@@ -48,6 +49,7 @@ public GeneralSettings(Map objectMap) {
spawnerDropSuppression = map.getValueOrDefault("spawnerDropSuppression", spawnerDropSuppression);
ignoreSpawnerMobs = map.getValueOrDefault("ignoreSpawnerMobs", ignoreSpawnerMobs);
blockedCommands = map.getValueOrDefault("blockedCommands", blockedCommands);
+ blockedCommands = blockedCommands.stream().map(String::toLowerCase).collect(Collectors.toList());
if (beeFix) {
BloodNight.logger().info("§4Bee Fix is enabled. This feature should be used with care.");
}
@@ -57,7 +59,8 @@ public GeneralSettings() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("language", language)
.add("prefix", prefix)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/BossBarSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/BossBarSettings.java
index 5dfb9e8a..0b99eb8f 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/BossBarSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/BossBarSettings.java
@@ -68,7 +68,8 @@ public void setTitle(String title) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("enabled", enabled)
.add("title", title)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSelection.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSelection.java
index 410918a1..2539f1ba 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSelection.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSelection.java
@@ -16,6 +16,7 @@
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
+import java.time.LocalDateTime;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -32,6 +33,16 @@ public class NightSelection implements ConfigurationSerializable {
*/
private int probability = 60;
+ private Map weekDay = new HashMap() {{
+ put(0, 10);
+ put(1, 0);
+ put(2, 0);
+ put(3, 0);
+ put(4, 10);
+ put(5, 80);
+ put(6, 90);
+ }};
+
private Map moonPhase = new HashMap() {{
put(0, 0);
put(1, 10);
@@ -92,6 +103,8 @@ public NightSelection(Map objectMap) {
moonPhase.entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).collect(Collectors.toList())));
phaseCustom = parsePhase(map.getValueOrDefault("phasesCustom",
phaseCustom.entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).collect(Collectors.toList())));
+ phaseCustom = parsePhase(map.getValueOrDefault("weekDay",
+ weekDay.entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).collect(Collectors.toList())));
verifyPhases();
currPhase = map.getValueOrDefault("currPhase", currPhase);
period = map.getValueOrDefault("period", period);
@@ -131,14 +144,22 @@ public int getPhaseProbability(int phase) {
@Override
@NotNull
public Map serialize() {
- List phases = this.moonPhase.entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).collect(Collectors.toList());
- List phasesCustom = this.phaseCustom.entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).collect(Collectors.toList());
+ List phases = this.moonPhase.entrySet().stream()
+ .map(e -> e.getKey() + ":" + e.getValue())
+ .collect(Collectors.toList());
+ List phasesCustom = this.phaseCustom.entrySet().stream()
+ .map(e -> e.getKey() + ":" + e.getValue())
+ .collect(Collectors.toList());
+ List weekDay = this.weekDay.entrySet().stream()
+ .map(e -> e.getKey() + ":" + e.getValue())
+ .collect(Collectors.toList());
return SerializationUtil.newBuilder()
.add("probability", probability)
.add("nightSelectionType", nightSelectionType.name())
.add("phases", phases)
.add("phasesCustom", phasesCustom)
+ .add("weekDay", weekDay)
.add("currPhase", currPhase)
.add("period", period)
.add("currCurvePos", currCurvePos)
@@ -159,6 +180,10 @@ public void setMoonPhase(int phase, int probability) {
moonPhase.put(phase, probability);
}
+ public void setWeekDay(int day, int probability) {
+ weekDay.put(day, probability);
+ }
+
public void setPhaseCount(int phaseCount) {
Map newPhases = new HashMap<>();
for (int i = 0; i < phaseCount; i++) {
@@ -242,6 +267,9 @@ public int getNextProbability(World world, int nightOffset) {
(double) getMinCurveVal()), pos);
}
return (int) curveProb;
+ case WEEKDAY:
+ int value = (LocalDateTime.now().getDayOfWeek().getValue() - 1 + nightOffset) % 7;
+ return weekDay.get(value);
}
return 0;
}
@@ -266,6 +294,31 @@ public void upcount() {
}
}
+ @Override
+ public String toString() {
+ String phases;
+ switch (nightSelectionType) {
+ case RANDOM:
+ return String.format("Mode: %s | Prob: %s", nightSelectionType, probability);
+ case MOON_PHASE:
+ case REAL_MOON_PHASE:
+ phases = getMoonPhase().entrySet().stream()
+ .map(e -> e.getKey() + ":" + e.getValue())
+ .collect(Collectors.joining(" | "));
+ return String.format("Mode: %s | Phases: %s", nightSelectionType, phases);
+ case INTERVAL:
+ return String.format("Mode: %s | Interval %d of %d with Prob %d", nightSelectionType, curInterval, interval - 1, intervalProbability);
+ case PHASE:
+ phases = getPhaseCustom().entrySet().stream()
+ .map(e -> e.getKey() + ":" + e.getValue())
+ .collect(Collectors.joining(" | "));
+ return String.format("Mode: %s | Phases: %s", nightSelectionType, phases);
+ case CURVE:
+ return String.format("Mode: %s | Pos %d on curve between %d and %d", nightSelectionType, currCurvePos, minCurveVal, maxCurveVal);
+ }
+ return "NightSelection{}";
+ }
+
public enum NightSelectionType {
/**
* Determine bloodnight based on a random value.
@@ -290,31 +343,10 @@ public enum NightSelectionType {
/**
* Determine bloodnight based on a smooth curve with a fixed length and a max and min probability.
*/
- CURVE
- }
-
- @Override
- public String toString() {
- String phases;
- switch (nightSelectionType) {
- case RANDOM:
- return String.format("Mode: %s | Prob: %s", nightSelectionType, probability);
- case MOON_PHASE:
- case REAL_MOON_PHASE:
- phases = getMoonPhase().entrySet().stream()
- .map(e -> e.getKey() + ":" + e.getValue())
- .collect(Collectors.joining(" | "));
- return String.format("Mode: %s | Phases: %s", nightSelectionType, phases);
- case INTERVAL:
- return String.format("Mode: %s | Interval %d of %d with Prob %d", nightSelectionType, curInterval, interval - 1, intervalProbability);
- case PHASE:
- phases = getPhaseCustom().entrySet().stream()
- .map(e -> e.getKey() + ":" + e.getValue())
- .collect(Collectors.joining(" | "));
- return String.format("Mode: %s | Phases: %s", nightSelectionType, phases);
- case CURVE:
- return String.format("Mode: %s | Pos %d on curve between %d and %d", nightSelectionType, currCurvePos, minCurveVal, maxCurveVal);
- }
- return "NightSelection{}";
+ CURVE,
+ /**
+ * Determine bloodnight based on the current real week day.
+ */
+ WEEKDAY
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSettings.java
index c80681f5..19a08143 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/NightSettings.java
@@ -82,7 +82,8 @@ public void setNightDuration(int nightDuration) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("skippable", skippable)
.add("nightBegin", nightBegin)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/WorldSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/WorldSettings.java
index fa1a5b37..837f00a1 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/WorldSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/WorldSettings.java
@@ -49,7 +49,8 @@ public WorldSettings(String world) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("world", worldName)
.add("enabled", enabled)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActionSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActionSettings.java
index fe9a912f..48441aea 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActionSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActionSettings.java
@@ -27,7 +27,8 @@ public DeathActionSettings() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("mobDeathActions", mobDeathActions)
.add("playerDeathActions", playerDeathActions)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActions.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActions.java
index 3cd55298..dbd08bed 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActions.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/DeathActions.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.config.worldsettings.deathactions;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.LightningSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.ShockwaveSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.LightningSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.ShockwaveSettings;
import de.eldoria.eldoutilities.serialization.SerializationUtil;
import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
import lombok.Getter;
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PlayerDeathActions.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PlayerDeathActions.java
index 2e3ba7e5..1a788af1 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PlayerDeathActions.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PlayerDeathActions.java
@@ -1,5 +1,6 @@
package de.eldoria.bloodnight.config.worldsettings.deathactions;
+import de.eldoria.bloodnight.bloodmob.settings.util.PotionEffectSettings;
import de.eldoria.eldoutilities.serialization.SerializationUtil;
import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
import lombok.Getter;
@@ -45,7 +46,8 @@ public PlayerDeathActions() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder(super.serialize())
.add("deathCommands", deathCommands)
.add("loseInvProbability", loseInvProbability)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/Drop.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/Drop.java
deleted file mode 100644
index 2b830441..00000000
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/Drop.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package de.eldoria.bloodnight.config.worldsettings.mobsettings;
-
-import de.eldoria.bloodnight.core.BloodNight;
-import de.eldoria.eldoutilities.localization.ILocalizer;
-import de.eldoria.eldoutilities.serialization.SerializationUtil;
-import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
-import lombok.Getter;
-import org.bukkit.Bukkit;
-import org.bukkit.NamespacedKey;
-import org.bukkit.configuration.serialization.ConfigurationSerializable;
-import org.bukkit.configuration.serialization.SerializableAs;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.persistence.PersistentDataContainer;
-import org.bukkit.persistence.PersistentDataType;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Getter
-@SerializableAs("bloodNightDrop")
-public class Drop implements ConfigurationSerializable {
- private static final NamespacedKey WEIGHT_KEY = BloodNight.getNamespacedKey("dropWeight");
- private final ItemStack item;
- private final int weight;
-
- public Drop(Map objectMap) {
- TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
- item = map.getValue("item");
- weight = map.getValue("weight");
- }
-
- public Drop(ItemStack item, int weight) {
- this.item = item;
- this.weight = weight;
- }
-
- public static Drop fromItemStack(ItemStack itemStack) {
- if (itemStack == null) return null;
- return new Drop(removeWeight(itemStack), getWeightFromItemStack(itemStack));
- }
-
- public static void changeWeight(ItemStack item, int change) {
- int currWeight = getWeightFromItemStack(item);
- int newWeight = Math.min(Math.max(currWeight + change, 1), 100);
- setWeight(item, newWeight);
- Pattern weight = getRegexWeight();
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- List lore = itemMeta.hasLore() ? itemMeta.getLore() : new ArrayList<>();
- if (lore.isEmpty()) {
- lore.add(getWeightString(newWeight));
- } else {
- Matcher matcher = weight.matcher(lore.get(lore.size() - 1));
- if (matcher.find()) {
- lore.set(lore.size() - 1, getWeightString(newWeight));
- } else {
- lore.add(getWeightString(newWeight));
- }
- }
- itemMeta.setLore(lore);
- item.setItemMeta(itemMeta);
- }
-
- public static ItemStack removeWeight(ItemStack item) {
- Pattern weight = getRegexWeight();
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- List lore = itemMeta.hasLore() ? itemMeta.getLore() : new ArrayList<>();
- if (lore.isEmpty()) {
- return item;
- } else {
- Matcher matcher = weight.matcher(lore.get(lore.size() - 1));
- if (matcher.find()) {
- lore.remove(lore.size() - 1);
- } else {
- return item;
- }
- }
- ItemStack newItem = item.clone();
- itemMeta.setLore(lore);
- PersistentDataContainer container = itemMeta.getPersistentDataContainer();
- if (container.has(WEIGHT_KEY, PersistentDataType.INTEGER)) {
- container.remove(WEIGHT_KEY);
- }
- newItem.setItemMeta(itemMeta);
- return newItem;
- }
-
- public static int getWeightFromItemStack(ItemStack item) {
- setWeightIfNotSet(item, 1);
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
- return dataContainer.get(WEIGHT_KEY, PersistentDataType.INTEGER);
- }
-
- private static Pattern getRegexWeight() {
- return Pattern.compile("§6" + ILocalizer.getPluginLocalizer(BloodNight.class).getMessage("drops.weight") + ":\\s([0-9]+?)");
- }
-
- private static void setWeight(ItemStack item, int weight) {
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
- dataContainer.set(WEIGHT_KEY, PersistentDataType.INTEGER, weight);
- item.setItemMeta(itemMeta);
- }
-
- private static void setWeightIfNotSet(ItemStack item, int weight) {
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
- if (!dataContainer.has(WEIGHT_KEY, PersistentDataType.INTEGER)) {
- setWeight(item, weight);
- }
- }
-
- private static String getWeightString(int weight) {
- return "§6" + ILocalizer.getPluginLocalizer(BloodNight.class).getMessage("drops.weight") + ": " + weight;
- }
-
- @Override
- public @NotNull Map serialize() {
- return SerializationUtil.newBuilder()
- .add("item", item)
- .add("weight", weight)
- .build();
- }
-
- public ItemStack getWeightedItem() {
- ItemStack newItem = item.clone();
- setWeight(newItem, weight);
- return newItem;
- }
-
- public ItemStack getItem() {
- return item.clone();
- }
-
- public ItemStack getItemWithLoreWeight() {
- ItemMeta itemMeta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType());
- List lore = itemMeta.hasLore() ? itemMeta.getLore() : new ArrayList<>();
- lore.add("§6Weight: " + getWeight());
- itemMeta.setLore(lore);
- ItemStack newItem = item.clone();
- newItem.setItemMeta(itemMeta);
- return newItem;
- }
-}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSetting.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSetting.java
index 25a130d5..9c93ca17 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSetting.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSetting.java
@@ -1,6 +1,8 @@
package de.eldoria.bloodnight.config.worldsettings.mobsettings;
import com.google.common.base.Objects;
+import de.eldoria.bloodnight.bloodmob.settings.MobValueModifier;
+import de.eldoria.bloodnight.bloodmob.drop.Drop;
import de.eldoria.eldoutilities.serialization.SerializationUtil;
import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
import de.eldoria.eldoutilities.utils.EnumUtil;
@@ -87,7 +89,8 @@ public int getOverridenDropAmount(int dropAmount) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("mobName", mobName)
.add("displayName", displayName)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSettings.java
index 63d91db5..67014fb3 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobSettings.java
@@ -1,5 +1,6 @@
package de.eldoria.bloodnight.config.worldsettings.mobsettings;
+import de.eldoria.bloodnight.bloodmob.drop.Drop;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.core.mobfactory.MobFactory;
import de.eldoria.bloodnight.core.mobfactory.MobGroup;
@@ -95,7 +96,8 @@ public MobSettings() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("vanillaMobSettings", vanillaMobSettings)
.add("displayMobNames", displayMobNames)
@@ -145,7 +147,7 @@ public List getDrops(int dropAmount) {
public List getDrops(List totalDrops, int minDrops, int dropAmount) {
if (dropAmount == 0) return new ArrayList<>();
- int totalWeight = totalDrops.stream().mapToInt(Drop::getWeight).sum();
+ int totalWeight = totalDrops.stream().mapToInt(Drop::weight).sum();
ThreadLocalRandom current = ThreadLocalRandom.current();
int nextInt = current.nextInt(minDrops, dropAmount + 1);
@@ -155,9 +157,11 @@ public List getDrops(List totalDrops, int minDrops, int dropAmo
for (int i = 0; i < nextInt; i++) {
int goal = current.nextInt(totalWeight + 1);
for (Drop drop : totalDrops) {
- currentWeight += drop.getWeight();
+ currentWeight += drop.weight();
if (currentWeight < goal) continue;
- result.add(new ItemStack(drop.getItem().clone()));
+ //todo
+
+ //result.add(new ItemStack(drop.getItemId()));
break;
}
}
@@ -222,7 +226,8 @@ public MobTypes(Map objectMap) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
SerializationUtil.Builder builder = SerializationUtil.newBuilder();
for (Map.Entry> entry : mobSettings.entrySet()) {
builder.add(entry.getKey(), new ArrayList<>(entry.getValue()));
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobValueModifier.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobValueModifier.java
deleted file mode 100644
index 831d3887..00000000
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/MobValueModifier.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package de.eldoria.bloodnight.config.worldsettings.mobsettings;
-
-public enum MobValueModifier {
- DEFAULT, MULTIPLY, VALUE
-}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaMobSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaMobSettings.java
index 5f5ed0db..0b5dbe92 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaMobSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaMobSettings.java
@@ -1,5 +1,6 @@
package de.eldoria.bloodnight.config.worldsettings.mobsettings;
+import de.eldoria.bloodnight.bloodmob.settings.VanillaDropMode;
import de.eldoria.eldoutilities.serialization.SerializationUtil;
import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
import de.eldoria.eldoutilities.utils.EnumUtil;
@@ -46,7 +47,8 @@ public VanillaMobSettings(Map objectMap) {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("damageMultiplier", damageMultiplier)
.add("healthMultiplier", healthMultiplier)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundEntry.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundEntry.java
index 96291400..7c44e2c7 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundEntry.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundEntry.java
@@ -70,7 +70,8 @@ private double getVolume() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("sound", sound.name())
.add("pitch", pitch)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundSettings.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundSettings.java
index 7f03272b..aef4927f 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundSettings.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/sound/SoundSettings.java
@@ -81,7 +81,8 @@ public int getWaitSeconds() {
}
@Override
- public @NotNull Map serialize() {
+ public @NotNull
+ Map serialize() {
return SerializationUtil.newBuilder()
.add("minInterval", minInterval)
.add("maxInterval", maxInterval)
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/BloodNight.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/BloodNight.java
index 908e9f93..c6c8e14d 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/BloodNight.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/BloodNight.java
@@ -12,10 +12,10 @@
import de.eldoria.bloodnight.config.worldsettings.deathactions.DeathActionSettings;
import de.eldoria.bloodnight.config.worldsettings.deathactions.MobDeathActions;
import de.eldoria.bloodnight.config.worldsettings.deathactions.PlayerDeathActions;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.PotionEffectSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.LightningSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.ShockwaveSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.Drop;
+import de.eldoria.bloodnight.bloodmob.settings.util.PotionEffectSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.LightningSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.ShockwaveSettings;
+import de.eldoria.bloodnight.bloodmob.drop.Drop;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSetting;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.VanillaMobSettings;
@@ -34,7 +34,6 @@
import de.eldoria.eldoutilities.bstats.charts.MultiLineChart;
import de.eldoria.eldoutilities.localization.ILocalizer;
import de.eldoria.eldoutilities.messages.MessageSender;
-import de.eldoria.eldoutilities.plugin.EldoPlugin;
import de.eldoria.eldoutilities.updater.Updater;
import de.eldoria.eldoutilities.updater.butlerupdater.ButlerUpdateData;
import lombok.Getter;
@@ -45,7 +44,7 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
-public class BloodNight extends EldoPlugin {
+public class BloodNight extends ABloodNight {
@Getter
private static BloodNight instance;
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/MobManager.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/MobManager.java
index 1664c88e..7b14a54e 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/MobManager.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/MobManager.java
@@ -1,11 +1,12 @@
package de.eldoria.bloodnight.core.manager.mobmanager;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.config.Configuration;
import de.eldoria.bloodnight.config.worldsettings.WorldSettings;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.ShockwaveSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.ShockwaveSettings;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSetting;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
-import de.eldoria.bloodnight.config.worldsettings.mobsettings.VanillaDropMode;
+import de.eldoria.bloodnight.bloodmob.settings.VanillaDropMode;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.VanillaMobSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.core.manager.nightmanager.NightManager;
@@ -13,7 +14,6 @@
import de.eldoria.bloodnight.core.mobfactory.WorldMobFactory;
import de.eldoria.bloodnight.hooks.mythicmobs.MythicMobUtil;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
import de.eldoria.eldoutilities.entityutils.ProjectileSender;
import de.eldoria.eldoutilities.entityutils.ProjectileUtil;
import de.eldoria.eldoutilities.scheduling.DelayedActions;
@@ -112,7 +112,7 @@ public void onPlayerDamage(EntityDamageByEntityEvent event) {
MobSettings settings = configuration.getWorldSettings(oponent.getLocation().getWorld().getName()).getMobSettings();
// If it is a special mob it already has a custom health.
- if (SpecialMobUtil.isSpecialMob(damager)) return;
+ if (BloodMobUtil.isSpecialMob(damager)) return;
if (oponent.getType() != EntityType.PLAYER) return;
@@ -152,7 +152,7 @@ public void onEntityDamage(EntityDamageByEntityEvent event) {
if (!(oponent instanceof Monster || oponent instanceof Boss)) return;
// Reduce damage for vanilla mobs
- if (!SpecialMobUtil.isSpecialMob(oponent)) {
+ if (!BloodMobUtil.isSpecialMob(oponent)) {
VanillaMobSettings vanillaMobSettings = configuration.getWorldSettings(oponent.getLocation().getWorld().getName()).getMobSettings().getVanillaMobSettings();
event.setDamage(event.getDamage() / vanillaMobSettings.getHealthMultiplier());
}
@@ -178,8 +178,8 @@ public void onEntityKill(EntityDeathEvent event) {
WorldSettings worldSettings = configuration.getWorldSettings(entity.getWorld());
ShockwaveSettings shockwaveSettings = worldSettings.getDeathActionSettings().getMobDeathActions().getShockwaveSettings();
- SpecialMobUtil.dispatchShockwave(shockwaveSettings, event.getEntity().getLocation());
- SpecialMobUtil.dispatchLightning(worldSettings.getDeathActionSettings().getMobDeathActions().getLightningSettings(), event.getEntity().getLocation());
+ BloodMobUtil.dispatchShockwave(shockwaveSettings, event.getEntity().getLocation());
+ BloodMobUtil.dispatchLightning(worldSettings.getDeathActionSettings().getMobDeathActions().getLightningSettings(), event.getEntity().getLocation());
if (configuration.getGeneralSettings().isSpawnerDropSuppression()) {
if (entity.getPersistentDataContainer().has(SPAWNER_SPAWNED, PersistentDataType.BYTE)) {
@@ -203,7 +203,7 @@ public void onEntityKill(EntityDeathEvent event) {
return;
}
- if (SpecialMobUtil.isExtension(entity)) {
+ if (BloodMobUtil.isExtension(entity)) {
BloodNight.logger().finer("Mob is extension. Ignore.");
return;
}
@@ -211,7 +211,7 @@ public void onEntityKill(EntityDeathEvent event) {
BloodNight.logger().fine("Entity " + entity.getCustomName() + " was killed by " + player.getName());
BloodNight.logger().fine("Attemt to drop items.");
- if (SpecialMobUtil.isSpecialMob(entity)) {
+ if (BloodMobUtil.isSpecialMob(entity)) {
if (!mobSettings.isNaturalDrops()) {
BloodNight.logger().fine("Natural Drops are disabled. Clear loot.");
event.getDrops().clear();
@@ -225,7 +225,7 @@ public void onEntityKill(EntityDeathEvent event) {
}
// add custom drops
- Optional specialMob = SpecialMobUtil.getSpecialMobType(entity);
+ Optional specialMob = BloodMobUtil.getSpecialMobType(entity);
if (!specialMob.isPresent()) {
BloodNight.logger().log(Level.WARNING, "No special type name was received from special mob.", new IllegalStateException());
return;
@@ -285,6 +285,7 @@ public void onEntityExplode(EntityExplodeEvent event) {
}
}
+
delayedActions.schedule(() -> specialMobManager.remove(event.getEntity()), 1);
}
@@ -293,7 +294,7 @@ private void onChunkLoad(ChunkLoadEvent event) {
WorldMobs worldMobs = specialMobManager.getWorldMobs(event.getWorld());
for (Entity entity : event.getChunk().getEntities()) {
Optional> remove = worldMobs.remove(entity.getUniqueId());
- if (SpecialMobUtil.isSpecialMob(entity)) {
+ if (BloodMobUtil.isSpecialMob(entity)) {
if (remove.isPresent()) {
remove.get().remove();
} else {
@@ -316,7 +317,7 @@ private void onChunkLoad(ChunkLoadEvent event) {
for (Bee entity : state.releaseEntities()) {
entites.incrementAndGet();
BloodNight.logger().finer("Checking entity with id " + entity.getEntityId() + " and " + entity.getUniqueId().toString());
- if (SpecialMobUtil.isSpecialMob(entity)) {
+ if (BloodMobUtil.isSpecialMob(entity)) {
entity.remove();
}
return true;
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/SpecialMobManager.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/SpecialMobManager.java
index 9276122f..8ec05af3 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/SpecialMobManager.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/mobmanager/SpecialMobManager.java
@@ -1,5 +1,6 @@
package de.eldoria.bloodnight.core.manager.mobmanager;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.config.Configuration;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSetting;
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
@@ -9,7 +10,6 @@
import de.eldoria.bloodnight.events.BloodNightEndEvent;
import de.eldoria.bloodnight.hooks.mythicmobs.MythicMobUtil;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
import de.eldoria.eldoutilities.entityutils.ProjectileSender;
import de.eldoria.eldoutilities.entityutils.ProjectileUtil;
import de.eldoria.eldoutilities.threading.IteratingTask;
@@ -42,7 +42,7 @@ public void wrapMob(Entity entity, MobFactory mobFactory) {
if (!(entity instanceof LivingEntity)) return;
// I will not try to wrap a special or mythic mob
- if (SpecialMobUtil.isSpecialMob(entity)) return;
+ if (BloodMobUtil.isSpecialMob(entity)) return;
if (MythicMobUtil.isMythicMob(entity)) return;
MobSettings mobSettings = configuration.getWorldSettings(entity.getWorld().getName()).getMobSettings();
@@ -103,9 +103,9 @@ public void onProjectileHit(ProjectileHitEvent event) {
@EventHandler
public void onDeath(EntityDeathEvent event) {
- if (SpecialMobUtil.isSpecialMob(event.getEntity())) {
- if (SpecialMobUtil.isExtension(event.getEntity())) {
- Optional baseUUID = SpecialMobUtil.getBaseUUID(event.getEntity());
+ if (BloodMobUtil.isSpecialMob(event.getEntity())) {
+ if (BloodMobUtil.isExtension(event.getEntity())) {
+ Optional baseUUID = BloodMobUtil.getBaseUUID(event.getEntity());
if (!baseUUID.isPresent()) {
return;
}
@@ -133,12 +133,12 @@ public void onExplosionEvent(EntityExplodeEvent event) {
@EventHandler
public void onTargetEvent(EntityTargetEvent event) {
- if (event.getTarget() != null && SpecialMobUtil.isSpecialMob(event.getTarget())) {
+ if (event.getTarget() != null && BloodMobUtil.isSpecialMob(event.getTarget())) {
event.setCancelled(true);
return;
}
- if (!SpecialMobUtil.isSpecialMob(event.getEntity())) {
+ if (!BloodMobUtil.isSpecialMob(event.getEntity())) {
return;
}
@@ -155,9 +155,9 @@ public void onTargetEvent(EntityTargetEvent event) {
@EventHandler
public void onDamage(EntityDamageEvent event) {
- if (SpecialMobUtil.isSpecialMob(event.getEntity())) {
- if (SpecialMobUtil.isExtension(event.getEntity())) {
- Optional baseUUID = SpecialMobUtil.getBaseUUID(event.getEntity());
+ if (BloodMobUtil.isSpecialMob(event.getEntity())) {
+ if (BloodMobUtil.isExtension(event.getEntity())) {
+ Optional baseUUID = BloodMobUtil.getBaseUUID(event.getEntity());
if (!baseUUID.isPresent()) {
return;
}
@@ -170,9 +170,9 @@ public void onDamage(EntityDamageEvent event) {
@EventHandler
public void onDamageByEntity(EntityDamageByEntityEvent event) {
- if (SpecialMobUtil.isSpecialMob(event.getEntity())) {
- if (SpecialMobUtil.isExtension(event.getEntity())) {
- Optional baseUUID = SpecialMobUtil.getBaseUUID(event.getEntity());
+ if (BloodMobUtil.isSpecialMob(event.getEntity())) {
+ if (BloodMobUtil.isExtension(event.getEntity())) {
+ Optional baseUUID = BloodMobUtil.getBaseUUID(event.getEntity());
if (!baseUUID.isPresent()) {
return;
}
@@ -209,7 +209,7 @@ public void onBloodNightEnd(BloodNightEndEvent event) {
if (!(e instanceof LivingEntity)) {
return false;
}
- if (SpecialMobUtil.isSpecialMob(e)) {
+ if (BloodMobUtil.isSpecialMob(e)) {
lostEntities.add(e);
return true;
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/NightManager.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/NightManager.java
index 77cb1c02..b1b171e9 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/NightManager.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/NightManager.java
@@ -6,13 +6,13 @@
import de.eldoria.bloodnight.config.worldsettings.NightSettings;
import de.eldoria.bloodnight.config.worldsettings.WorldSettings;
import de.eldoria.bloodnight.config.worldsettings.deathactions.PlayerDeathActions;
-import de.eldoria.bloodnight.config.worldsettings.deathactions.PotionEffectSettings;
+import de.eldoria.bloodnight.bloodmob.settings.util.PotionEffectSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.core.manager.nightmanager.util.BloodNightData;
import de.eldoria.bloodnight.core.manager.nightmanager.util.NightUtil;
import de.eldoria.bloodnight.events.BloodNightBeginEvent;
import de.eldoria.bloodnight.events.BloodNightEndEvent;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.util.C;
import de.eldoria.eldoutilities.core.EldoUtilities;
import de.eldoria.eldoutilities.localization.ILocalizer;
@@ -300,8 +300,8 @@ public void onPlayerDeath(PlayerDeathEvent event) {
PlayerDeathActions actions = configuration.getWorldSettings(event.getEntity().getWorld())
.getDeathActionSettings()
.getPlayerDeathActions();
- SpecialMobUtil.dispatchShockwave(actions.getShockwaveSettings(), event.getEntity().getLocation());
- SpecialMobUtil.dispatchLightning(actions.getLightningSettings(), event.getEntity().getLocation());
+ BloodMobUtil.dispatchShockwave(actions.getShockwaveSettings(), event.getEntity().getLocation());
+ BloodMobUtil.dispatchLightning(actions.getLightningSettings(), event.getEntity().getLocation());
if (actions.getLoseInvProbability() > ThreadLocalRandom.current().nextInt(100)) {
event.getDrops().clear();
@@ -322,6 +322,7 @@ public void onPlayerRespawn(PlayerRespawnEvent event) {
PlayerDeathActions actions = configuration.getWorldSettings(player.getWorld())
.getDeathActionSettings()
.getPlayerDeathActions();
+ // TODO: Player bed should get repspawn effects
if (!isBloodNightActive(player.getWorld()) || event.isBedSpawn() || event.isAnchorSpawn()) {
return;
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/TimeManager.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/TimeManager.java
index 1c2bf0cc..cdf5de35 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/TimeManager.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/manager/nightmanager/TimeManager.java
@@ -21,13 +21,12 @@
public class TimeManager extends BukkitRunnable implements Listener {
private final Configuration configuration;
private final NightManager nightManager;
- private boolean ignoreSkip = false;
/**
* Map contains for every active world a boolean if it is currently night.
*/
private final Map timeState = new HashMap<>();
-
private final Map customTimes = new HashMap<>();
+ private boolean ignoreSkip = false;
// <--- World consistency ---> //
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/mobfactory/MobFactory.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/mobfactory/MobFactory.java
index 6f415930..56254552 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/mobfactory/MobFactory.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/core/mobfactory/MobFactory.java
@@ -4,7 +4,7 @@
import de.eldoria.bloodnight.config.worldsettings.mobsettings.MobSettings;
import de.eldoria.bloodnight.core.BloodNight;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.eldoutilities.localization.ILocalizer;
import de.eldoria.eldoutilities.utils.AttributeUtil;
import lombok.Getter;
@@ -28,7 +28,7 @@ public MobFactory(EntityType entityType, Class extends SpecialMob>> clazz, F
}
public SpecialMob> wrap(LivingEntity entity, MobSettings mobSettings, MobSetting mobSetting) {
- SpecialMobUtil.tagSpecialMob(entity);
+ BloodMobUtil.tagSpecialMob(entity);
applySettings(entity, mobSettings, mobSetting);
return factory.apply(entity);
}
@@ -38,7 +38,7 @@ private void applySettings(LivingEntity entity, MobSettings mobSettings, MobSett
AttributeUtil.setAttributeValue(entity, damage.getAttribute(), Math.min(mobSetting.applyDamage(damage.getValue(), mobSettings.getDamageMultiplier()), 2048));
AttributeInstance health = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH);
AttributeUtil.setAttributeValue(entity, health.getAttribute(), Math.min(mobSetting.applyHealth(health.getValue(), mobSettings.getHealthModifier()), 2048));
- SpecialMobUtil.setSpecialMobType(entity, mobSetting.getMobName());
+ BloodMobUtil.setSpecialMobType(entity, mobSetting.getMobName());
entity.setHealth(health.getValue());
String displayName = mobSetting.getDisplayName();
if (displayName.trim().isEmpty()) {
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMob.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMob.java
index 34e7a166..31e2adb0 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMob.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMob.java
@@ -137,8 +137,8 @@ public void onHit(EntityDamageByEntityEvent event) {
* If you override this just remove the extension and call super afterwards.
*/
public void remove() {
- if (getBaseEntity().isValid()) {
- getBaseEntity().remove();
+ if (baseEntity.isValid()) {
+ baseEntity.remove();
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/ExtendedSpecialMob.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/ExtendedSpecialMob.java
index 8dfae36e..7a9b5d78 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/ExtendedSpecialMob.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/ExtendedSpecialMob.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.specialmobs.StatSource;
import de.eldoria.eldoutilities.utils.AttributeUtil;
import lombok.Getter;
@@ -46,7 +46,7 @@ public ExtendedSpecialMob(T carrier, U passenger, StatSource statSource) {
* @param passenger to spawn
*/
public ExtendedSpecialMob(T carrier, EntityType passenger) {
- this(carrier, SpecialMobUtil.spawnAndMount(carrier, passenger), StatSource.CARRIER);
+ this(carrier, BloodMobUtil.spawnAndMount(carrier, passenger), StatSource.CARRIER);
}
/**
@@ -56,7 +56,7 @@ public ExtendedSpecialMob(T carrier, EntityType passenger) {
* @param passenger passenger to bind
*/
public ExtendedSpecialMob(EntityType carrier, U passenger) {
- this(SpecialMobUtil.spawnAndMount(carrier, passenger), passenger, StatSource.PASSENGER);
+ this(BloodMobUtil.spawnAndMount(carrier, passenger), passenger, StatSource.PASSENGER);
}
/**
@@ -99,7 +99,7 @@ public void onTargetEvent(EntityTargetEvent event) {
*/
@Override
public void onDamage(EntityDamageEvent event) {
- SpecialMobUtil.handleExtendedEntityDamage(getBaseEntity(), getPassenger(), event);
+ BloodMobUtil.handleExtendedEntityDamage(getBaseEntity(), getPassenger(), event);
}
/**
@@ -111,7 +111,7 @@ public void onDamage(EntityDamageEvent event) {
*/
@Override
public void onExtensionDamage(EntityDamageEvent event) {
- SpecialMobUtil.handleExtendedEntityDamage(getPassenger(), getBaseEntity(), event);
+ BloodMobUtil.handleExtendedEntityDamage(getPassenger(), getBaseEntity(), event);
}
/**
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/EnderCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/EnderCreeper.java
index 1e7ad4aa..77811e35 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/EnderCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/EnderCreeper.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.core.BloodNight;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.Creeper;
@@ -23,7 +23,7 @@ public EnderCreeper(Creeper creeper) {
@Override
public void tick() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.PURPLE, 2), 5);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.PURPLE, 2), 5);
teleportToTarget();
}
@@ -63,13 +63,13 @@ private void teleportToTarget() {
BloodNight.logger().finer("Teleport from " + getBaseEntity().getLocation() + " to " + newLoc);
getBaseEntity().teleport(newLoc);
lastTeleport = Instant.now();
- SpecialMobUtil.spawnParticlesAround(loc, Particle.PORTAL, 10);
+ BloodMobUtil.spawnParticlesAround(loc, Particle.PORTAL, 10);
getBaseEntity().playEffect(EntityEffect.ENTITY_POOF);
}
if (lastTeleport.isBefore(Instant.now().minusSeconds(8))) {
getBaseEntity().teleport(target.getLocation());
lastTeleport = Instant.now();
- SpecialMobUtil.spawnParticlesAround(loc, Particle.PORTAL, 10);
+ BloodMobUtil.spawnParticlesAround(loc, Particle.PORTAL, 10);
getBaseEntity().playEffect(EntityEffect.ENTITY_POOF);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/GhostCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/GhostCreeper.java
index a8d2e6e3..c30fdc82 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/GhostCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/GhostCreeper.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.core.BloodNight;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
import de.eldoria.bloodnight.specialmobs.mobs.ExtendedSpecialMob;
import de.eldoria.eldoutilities.container.Triple;
import de.eldoria.eldoutilities.crossversion.ServerVersion;
@@ -47,9 +47,9 @@ public void run() {
@Override
public void tick() {
if (legacy) {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 4, false);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 4, false);
}
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, false);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, false);
super.tick();
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/NervousPoweredCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/NervousPoweredCreeper.java
index eb0a9f13..1754edc2 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/NervousPoweredCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/NervousPoweredCreeper.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Color;
import org.bukkit.Particle;
import org.bukkit.entity.Creeper;
@@ -12,12 +12,12 @@ public NervousPoweredCreeper(Creeper creeper) {
super(creeper);
setPowered(true);
setMaxFuseTicks(1);
- SpecialMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.RED, 5), 10);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.RED, 5), 10);
}
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 2, false);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 2, false);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/SpeedCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/SpeedCreeper.java
index 31cbfae2..2e929597 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/SpeedCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/SpeedCreeper.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.Creeper;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.potion.PotionEffectType;
@@ -13,7 +13,7 @@ public SpeedCreeper(Creeper creeper) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, true);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/ToxicCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/ToxicCreeper.java
index b86a77ac..623dfc7e 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/ToxicCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/ToxicCreeper.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
-import de.eldoria.bloodnight.specialmobs.effects.PotionCloud;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.PotionCloud;
import org.bukkit.Color;
import org.bukkit.Particle;
import org.bukkit.entity.Creeper;
@@ -18,7 +18,7 @@ public ToxicCreeper(Creeper creeper) {
@Override
public void tick() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.GREEN, 2), 5);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.GREEN, 2), 5);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/UnstableCreeper.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/UnstableCreeper.java
index 0e143100..7906be54 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/UnstableCreeper.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/creeper/UnstableCreeper.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.creeper;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Creeper;
import org.bukkit.event.entity.EntityDamageEvent;
@@ -18,7 +18,7 @@ public UnstableCreeper(Creeper creeper) {
@Override
public void tick() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.END_ROD, 2);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.END_ROD, 2);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/AbstractEnderman.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/AbstractEnderman.java
index 2f5f835d..876f4a01 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/AbstractEnderman.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/AbstractEnderman.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.enderman;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.GameMode;
import org.bukkit.Particle;
import org.bukkit.entity.*;
@@ -29,6 +29,6 @@ public void tick() {
@Override
public void onEnd() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.DRAGON_BREATH, 10);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.DRAGON_BREATH, 10);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/FearfulEnderman.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/FearfulEnderman.java
index 4678853a..ac5c5c70 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/FearfulEnderman.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/FearfulEnderman.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.enderman;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.EntityType;
@@ -17,7 +17,7 @@ public FearfulEnderman(Enderman enderman) {
@Override
public void tick() {
super.tick();
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_WITCH, 10);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_WITCH, 10);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/ToxicEnderman.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/ToxicEnderman.java
index da9aac1e..a546d894 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/ToxicEnderman.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/enderman/ToxicEnderman.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.enderman;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
-import de.eldoria.bloodnight.specialmobs.effects.PotionCloud;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.PotionCloud;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
@@ -18,7 +18,7 @@ public ToxicEnderman(Enderman enderman) {
@Override
public void tick() {
super.tick();
- SpecialMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.GREEN, 2), 5);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity().getLocation(), Particle.REDSTONE, new Particle.DustOptions(Color.GREEN, 2), 5);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/AbstractPhantom.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/AbstractPhantom.java
index 97c72af1..c822bef5 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/AbstractPhantom.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/AbstractPhantom.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.phantom;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Phantom;
@@ -13,6 +13,6 @@ protected AbstractPhantom(Phantom phantom) {
@Override
public void onEnd() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FearfulPhantom.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FearfulPhantom.java
index b5aee8be..338c72df 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FearfulPhantom.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FearfulPhantom.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.phantom;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Phantom;
@@ -15,7 +15,7 @@ public FearfulPhantom(Phantom phantom) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.GLOWING, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.GLOWING, 1, true);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FirePhantom.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FirePhantom.java
index f0a85757..de7ec071 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FirePhantom.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/FirePhantom.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.phantom;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.eldoutilities.utils.AttributeUtil;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Blaze;
@@ -18,7 +18,7 @@ public class FirePhantom extends AbstractPhantom {
public FirePhantom(Phantom phantom) {
super(phantom);
- blaze = SpecialMobUtil.spawnAndMount(getBaseEntity(), EntityType.BLAZE);
+ blaze = BloodMobUtil.spawnAndMount(getBaseEntity(), EntityType.BLAZE);
AttributeUtil.syncAttributeValue(phantom, blaze, Attribute.GENERIC_ATTACK_DAMAGE);
AttributeUtil.syncAttributeValue(phantom, blaze, Attribute.GENERIC_MAX_HEALTH);
}
@@ -34,12 +34,12 @@ public void onDamageByEntity(EntityDamageByEntityEvent event) {
@Override
public void onDamage(EntityDamageEvent event) {
- SpecialMobUtil.handleExtendedEntityDamage(getBaseEntity(), blaze, event);
+ BloodMobUtil.handleExtendedEntityDamage(getBaseEntity(), blaze, event);
}
@Override
public void onExtensionDamage(EntityDamageEvent event) {
- SpecialMobUtil.handleExtendedEntityDamage(blaze, getBaseEntity(), event);
+ BloodMobUtil.handleExtendedEntityDamage(blaze, getBaseEntity(), event);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/PhantomSoul.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/PhantomSoul.java
index 14b6c38f..d22b7f82 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/PhantomSoul.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/phantom/PhantomSoul.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.phantom;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Phantom;
@@ -16,8 +16,8 @@ public PhantomSoul(Phantom phantom) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.GLOWING, 1, true);
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, false);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.GLOWING, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, false);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/AbstractSkeleton.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/AbstractSkeleton.java
index ca788125..5b2809de 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/AbstractSkeleton.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/AbstractSkeleton.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.skeleton;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Skeleton;
@@ -12,6 +12,6 @@ public AbstractSkeleton(Skeleton skeleton) {
@Override
public void onEnd() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/InvisibleSkeleton.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/InvisibleSkeleton.java
index 8b9c84c6..19849551 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/InvisibleSkeleton.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/InvisibleSkeleton.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.skeleton;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.Skeleton;
import org.bukkit.potion.PotionEffectType;
@@ -11,6 +11,6 @@ public InvisibleSkeleton(Skeleton skeleton) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, false);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, false);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/MagicSkeleton.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/MagicSkeleton.java
index 85a8c250..971e3bbb 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/MagicSkeleton.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/skeleton/MagicSkeleton.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.skeleton;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Skeleton;
@@ -30,7 +30,7 @@ public MagicSkeleton(Skeleton skeleton) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.NIGHT_VISION, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.NIGHT_VISION, 1, true);
}
@Override
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/slime/ToxicSlime.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/slime/ToxicSlime.java
index d1cbee0f..220e8176 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/slime/ToxicSlime.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/slime/ToxicSlime.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.slime;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.Slime;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.potion.PotionEffect;
@@ -13,7 +13,7 @@ public ToxicSlime(Slime slime) {
@Override
public void onDeath(EntityDeathEvent event) {
- SpecialMobUtil.spawnLingeringPotionAt(event.getEntity().getLocation(),
+ BloodMobUtil.spawnLingeringPotionAt(event.getEntity().getLocation(),
new PotionEffect(PotionEffectType.POISON, 5 * 20, 2, true, true));
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/AbstractSpiderRider.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/AbstractSpiderRider.java
index 372a3df7..c248cde7 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/AbstractSpiderRider.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/AbstractSpiderRider.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.spider;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.specialmobs.StatSource;
import de.eldoria.bloodnight.specialmobs.mobs.ExtendedSpecialMob;
import org.bukkit.Particle;
@@ -31,6 +31,6 @@ public void onExtensionDamage(EntityDamageEvent event) {
@Override
public void onEnd() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/BlazeRider.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/BlazeRider.java
index bd10a269..67f6f7b2 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/BlazeRider.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/BlazeRider.java
@@ -1,12 +1,12 @@
package de.eldoria.bloodnight.specialmobs.mobs.spider;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Mob;
public class BlazeRider extends AbstractSpiderRider {
public BlazeRider(Mob carrier) {
- super(carrier, SpecialMobUtil.spawnAndMount(carrier, EntityType.BLAZE));
+ super(carrier, BloodMobUtil.spawnAndMount(carrier, EntityType.BLAZE));
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/SpeedSkeletonRider.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/SpeedSkeletonRider.java
index bcf19fe0..d7f29b6e 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/SpeedSkeletonRider.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/SpeedSkeletonRider.java
@@ -1,17 +1,17 @@
package de.eldoria.bloodnight.specialmobs.mobs.spider;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Mob;
import org.bukkit.potion.PotionEffectType;
public class SpeedSkeletonRider extends AbstractSpiderRider {
public SpeedSkeletonRider(Mob carrier) {
- super(carrier, SpecialMobUtil.spawnAndMount(carrier, EntityType.SKELETON));
+ super(carrier, BloodMobUtil.spawnAndMount(carrier, EntityType.SKELETON));
}
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 1, true);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/WitherSkeletonRider.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/WitherSkeletonRider.java
index 4beb4209..e77fb291 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/WitherSkeletonRider.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/spider/WitherSkeletonRider.java
@@ -1,17 +1,17 @@
package de.eldoria.bloodnight.specialmobs.mobs.spider;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Mob;
import org.bukkit.potion.PotionEffectType;
public class WitherSkeletonRider extends AbstractSpiderRider {
public WitherSkeletonRider(Mob carrier) {
- super(carrier, SpecialMobUtil.spawnAndMount(carrier, EntityType.WITHER_SKELETON));
+ super(carrier, BloodMobUtil.spawnAndMount(carrier, EntityType.WITHER_SKELETON));
}
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 1, true);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/AbstractWitch.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/AbstractWitch.java
index 49dcc7b6..e9016098 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/AbstractWitch.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/AbstractWitch.java
@@ -1,7 +1,7 @@
package de.eldoria.bloodnight.specialmobs.mobs.witch;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.bloodnight.specialmobs.SpecialMob;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Witch;
@@ -17,7 +17,7 @@ public AbstractWitch(Witch witch) {
@Override
public void onEnd() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.CAMPFIRE_COSY_SMOKE, 30);
}
protected void shot() {
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/FireWizard.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/FireWizard.java
index 63948f7d..4bb00191 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/FireWizard.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/FireWizard.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.witch;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import de.eldoria.eldoutilities.utils.ObjUtil;
import org.bukkit.Material;
import org.bukkit.Particle;
@@ -25,9 +25,9 @@ public FireWizard(Witch witch) {
public void tick() {
EntityEquipment equipment = getBaseEntity().getEquipment();
equipment.setItemInMainHand(new ItemStack(Material.FIRE_CHARGE));
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.DRIP_LAVA, 5);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.DRIP_LAVA, 5);
if (canShoot(5)) {
- SpecialMobUtil.launchProjectileOnTarget(getBaseEntity(), LargeFireball.class, 4);
+ BloodMobUtil.launchProjectileOnTarget(getBaseEntity(), LargeFireball.class, 4);
shot();
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/ThunderWizard.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/ThunderWizard.java
index ed2417e2..0e782a29 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/ThunderWizard.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/ThunderWizard.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.witch;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Particle;
import org.bukkit.entity.Witch;
import org.bukkit.event.entity.ProjectileLaunchEvent;
@@ -12,7 +12,7 @@ public ThunderWizard(Witch witch) {
@Override
public void tick() {
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_INSTANT, 15);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_INSTANT, 15);
if (canShoot(4) && getBaseEntity().getTarget() != null) {
getBaseEntity().getLocation().getWorld().strikeLightning(getBaseEntity().getTarget().getLocation());
shot();
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/WitherWizard.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/WitherWizard.java
index 8c8606de..c43d1935 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/WitherWizard.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/witch/WitherWizard.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.witch;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.entity.EntityType;
@@ -19,9 +19,9 @@ public WitherWizard(Witch witch) {
public void tick() {
EntityEquipment equipment = getBaseEntity().getEquipment();
equipment.setItemInMainHand(new ItemStack(Material.WITHER_SKELETON_SKULL));
- SpecialMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_INSTANT, 15);
+ BloodMobUtil.spawnParticlesAround(getBaseEntity(), Particle.SPELL_INSTANT, 15);
if (canShoot(5)) {
- SpecialMobUtil.launchProjectileOnTarget(getBaseEntity(), WitherSkull.class, 4);
+ BloodMobUtil.launchProjectileOnTarget(getBaseEntity(), WitherSkull.class, 4);
shot();
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/InvisibleZombie.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/InvisibleZombie.java
index 319de951..adf19519 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/InvisibleZombie.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/InvisibleZombie.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.zombie;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.Material;
import org.bukkit.entity.Zombie;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
@@ -28,7 +28,7 @@ public InvisibleZombie(Zombie zombie) {
@Override
public void tick() {
if (lastDamage.isBefore(Instant.now().minusSeconds(10))) {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.INVISIBILITY, 1, true);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/SpeedZombie.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/SpeedZombie.java
index e3117e42..54d3f58b 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/SpeedZombie.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/mobs/zombie/SpeedZombie.java
@@ -1,6 +1,6 @@
package de.eldoria.bloodnight.specialmobs.mobs.zombie;
-import de.eldoria.bloodnight.specialmobs.SpecialMobUtil;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
import org.bukkit.entity.Zombie;
import org.bukkit.potion.PotionEffectType;
@@ -11,6 +11,6 @@ public SpeedZombie(Zombie zombie) {
@Override
public void tick() {
- SpecialMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, true);
+ BloodMobUtil.addPotionEffect(getBaseEntity(), PotionEffectType.SPEED, 4, true);
}
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/Permissions.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/Permissions.java
index 00d283e1..8c35d9de 100644
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/Permissions.java
+++ b/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/Permissions.java
@@ -4,6 +4,8 @@
@UtilityClass
public class Permissions {
+ public static final String BASE = "bloodnight";
+
@UtilityClass
public static class Admin {
public static final String ADMIN = BASE + ".admin";
@@ -23,6 +25,4 @@ public static class Bypass {
public static final String BYPASS = BASE + ".bypass";
public static final String COMMAND_BLOCK = BYPASS + ".blockedcommands";
}
-
- public static final String BASE = "bloodnight";
}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/SomeCommand.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/SomeCommand.java
deleted file mode 100644
index 9f3d7bd8..00000000
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/SomeCommand.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package de.eldoria.bloodnight.util;
-
-import org.bukkit.Location;
-import org.bukkit.Material;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.server.ServerListPingEvent;
-import org.jetbrains.annotations.NotNull;
-
-public class SomeCommand implements CommandExecutor, Listener {
- @Override
- public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
- Player p = (Player) commandSender;
-
-
- Location baseLoc = p.getLocation();
- int horSize = 2, vertSize = 5;
- Location fire = null;
- for (int x = horSize * (-1); x <= horSize; x++) {
- for (int y = 0; y <= vertSize; y++) {
- Location loc = baseLoc.clone().add(x, y, 0);
- if (Math.abs(x) == vertSize || y == 0 || y == vertSize) loc.getBlock().setType(Material.OBSIDIAN);
- else if (y == 1 && x == 0) fire = loc;
- else loc.getBlock().setType(Material.AIR);
- }
- }
- fire.getBlock().setType(Material.FIRE);
- return true;
- }
-
- @EventHandler
- public void onServerPing(ServerListPingEvent event) {
-
- }
-}
diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/VectorUtil.java b/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/VectorUtil.java
deleted file mode 100644
index 85e1ad80..00000000
--- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/util/VectorUtil.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.eldoria.bloodnight.util;
-
-import lombok.experimental.UtilityClass;
-import org.bukkit.Location;
-import org.bukkit.util.Vector;
-
-@UtilityClass
-public class VectorUtil {
-
- public static Vector getDirectionVector(Location start, Location target) {
- return getDirectionVector(start.toVector(), target.toVector());
- }
-
- public static Vector getDirectionVector(Vector start, Vector target) {
- return new Vector(target.getX() - start.getX(), target.getY() - start.getY(), target.getZ() - start.getZ());
- }
-}
diff --git a/BloodNight-core/src/main/resources/plugin.yml b/BloodNight-core/src/main/resources/plugin.yml
index 89f3bfb8..a53e60a2 100644
--- a/BloodNight-core/src/main/resources/plugin.yml
+++ b/BloodNight-core/src/main/resources/plugin.yml
@@ -1,9 +1,9 @@
-name: ${plugin.name}
-description: ${plugin.description}
+name: ${name}
+description: ${description}
author: Hadde
-version: ${revision}
+version: ${version}
main: de.eldoria.bloodnight.core.BloodNight
-website: ${plugin.url}
+website: ${url}
api-version: 1.16
softdepend:
- Multiverse-Core
diff --git a/BloodNight-mobs/build.gradle.kts b/BloodNight-mobs/build.gradle.kts
new file mode 100644
index 00000000..0ad58e00
--- /dev/null
+++ b/BloodNight-mobs/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ java
+ id("de.eldoria.library-conventions")
+}
+
+description = "BloodNight-api"
+
+dependencies{
+ api(project(":BloodNight-api"))
+ api("com.fasterxml.jackson.module", "jackson-modules-java8", "2.12.3")
+
+}
+
+java{
+ withJavadocJar()
+ withSourcesJar()
+}
\ No newline at end of file
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/BloodMob.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/BloodMob.java
new file mode 100644
index 00000000..e145242a
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/BloodMob.java
@@ -0,0 +1,227 @@
+package de.eldoria.bloodnight.bloodmob;
+
+import de.eldoria.bloodnight.bloodmob.registry.items.ItemRegistry;
+import de.eldoria.bloodnight.bloodmob.settings.*;
+import de.eldoria.bloodnight.bloodmob.settings.mobsettings.BloodMobType;
+import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import de.eldoria.bloodnight.core.ABloodNight;
+import de.eldoria.eldoutilities.core.EldoUtilities;
+import de.eldoria.eldoutilities.localization.ILocalizer;
+import de.eldoria.eldoutilities.utils.AttributeUtil;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeInstance;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import org.bukkit.event.entity.*;
+
+import java.time.Instant;
+import java.util.Optional;
+
+public class BloodMob implements IBloodMob {
+ private final Mob base;
+ private final Mob extension;
+ private final MobConfiguration mobConfiguration;
+ private final Behaviour behaviour;
+ private Instant lastDamage = Instant.now();
+ private final ItemRegistry itemRegistry;
+
+ private BloodMob(Mob base, Mob extension, MobConfiguration mobConfiguration, ItemRegistry itemRegistry) {
+ this.base = base;
+ this.extension = extension;
+ this.mobConfiguration = mobConfiguration;
+ behaviour = mobConfiguration.behaviour();
+ this.itemRegistry = itemRegistry;
+ }
+
+ public static BloodMob construct(Mob base, WorldMobSettings mobSettings, MobConfiguration mobConfiguration, ItemRegistry itemRegistry) {
+ // tag mob as special mob
+ BloodMobUtil.tagSpecialMob(base);
+ // set attributes
+ AttributeInstance damage = base.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
+ AttributeUtil.setAttributeValue(base, damage.getAttribute(), Math.min(mobConfiguration.stats().applyDamage(damage.getValue(), mobSettings.damageMultiplier()), 2048));
+ AttributeInstance health = base.getAttribute(Attribute.GENERIC_MAX_HEALTH);
+ AttributeUtil.setAttributeValue(base, health.getAttribute(), Math.min(mobConfiguration.stats().applyHealth(health.getValue(), mobSettings.healthModifier()), 2048));
+ base.setHealth(health.getValue());
+ // flag with special mob type
+ BloodMobUtil.setSpecialMobType(base, mobConfiguration.identifier());
+ // set display name
+ Optional bloodMobType = BloodMobType.fromEntityType(base.getType());
+ if(!bloodMobType.isPresent()) return null;
+ TypeSetting typeSetting = mobConfiguration.wrapTypes().get(bloodMobType.get());
+ String name = typeSetting.name();
+ base.setCustomName(name);
+ base.setCustomNameVisible(mobSettings.isdisplayMobNames());
+ Equipment equipment = mobConfiguration.equipment();
+ if (equipment != null) {
+ equipment.apply(base, itemRegistry);
+ }
+
+ // build extension if required
+ if (mobConfiguration.isExtended()) {
+ Extension extentionSettings = mobConfiguration.extension();
+ // spawn and mount extension
+ Mob extension = addExtension(base, extentionSettings);
+ // sync names
+ extension.setCustomName(base.getCustomName());
+ extension.setCustomNameVisible(base.isCustomNameVisible());
+
+ // sync attributes
+ AttributeUtil.syncAttributeValue(base, extension, Attribute.GENERIC_ATTACK_DAMAGE);
+ AttributeUtil.syncAttributeValue(base, extension, Attribute.GENERIC_MAX_HEALTH);
+
+ extension.setInvulnerable(extentionSettings.isInvulnerable());
+ extension.setInvisible(extentionSettings.isInvisible());
+ if (extentionSettings.isClearEquipment()) {
+ EldoUtilities.getDelayedActions().schedule(() -> BloodMobUtil.clearEquipment(extension), 2);
+ }
+ equipment = extentionSettings.equipment();
+ if (equipment != null) {
+ equipment.apply(extension, itemRegistry);
+ }
+ return new BloodMob(base, extension, mobConfiguration, itemRegistry);
+ }
+
+ return new BloodMob(base, null, mobConfiguration, itemRegistry);
+ }
+
+ private static Mob addExtension(Mob base, Extension ext) {
+ switch (ext.extensionRole()) {
+ case CARRIER:
+ return BloodMobUtil.spawnAndMount(ext.extensionType().entityType(), base);
+ case PASSENGER:
+ return BloodMobUtil.spawnAndMount(base, ext.extensionType().entityType());
+ default:
+ throw new IllegalStateException("Unexpected value: " + ext.extensionRole());
+ }
+ }
+
+ @Override
+ public void tick() {
+
+ }
+
+ @Override
+ public void onEnd() {
+ }
+
+ @Override
+ public void onTeleport(EntityTeleportEvent event) {
+ }
+
+ @Override
+ public void onProjectileShoot(ProjectileLaunchEvent event) {
+ }
+
+ @Override
+ public void onProjectileHit(ProjectileHitEvent event) {
+ }
+
+ @Override
+ public void onDeath(EntityDeathEvent event) {
+ if (isExtended()) {
+ extension.damage(extension.getHealth(), base);
+ }
+ }
+
+ @Override
+ public void onKill(EntityDeathEvent event) {
+
+ }
+
+ @Override
+ public void onExplosionPrimeEvent(ExplosionPrimeEvent event) {
+
+ }
+
+ @Override
+ public void onExplosionEvent(EntityExplodeEvent event) {
+
+ }
+
+ @Override
+ public void onTargetEvent(EntityTargetEvent event) {
+ if (isExtended()) {
+ if (event.getTarget() == null) {
+ extension.setTarget(null);
+ return;
+ }
+
+ if (event.getTarget() instanceof LivingEntity) {
+ extension.setTarget((LivingEntity) event.getTarget());
+ }
+ }
+ }
+
+ @Override
+ public void onDamage(EntityDamageEvent event) {
+ BloodMobUtil.handleExtendedEntityDamage(getBase(), getExtension(), event);
+ }
+
+ @Override
+ public void onDamageByEntity(EntityDamageByEntityEvent event) {
+ lastDamage = Instant.now();
+ }
+
+ @Override
+ public void onHit(EntityDamageByEntityEvent event) {
+
+ }
+
+ @Override
+ public void remove() {
+ if (base.isValid()) {
+ base.remove();
+ }
+ if (isExtended() && extension.isValid()) {
+ extension.remove();
+ }
+ }
+
+ @Override
+ public void onExtensionDamage(EntityDamageEvent event) {
+ if (isExtended()) {
+ BloodMobUtil.handleExtendedEntityDamage(extension, base, event);
+ }
+ }
+
+ @Override
+ public void onExtensionDeath(EntityDeathEvent event) {
+ if (isExtended()) {
+ getBase().damage(getBase().getHealth(), event.getEntity().getKiller());
+ }
+ }
+
+ @Override
+ public boolean isValid() {
+ if (isExtended()) {
+ return base.isValid() && extension.isValid() && !base.getPassengers().isEmpty();
+ }
+ return base.isValid();
+ }
+
+ @Override
+ public Mob getBase() {
+ return base;
+ }
+
+ @Override
+ public Mob getExtension() {
+ return extension;
+ }
+
+ @Override
+ public boolean isExtended() {
+ return extension != null;
+ }
+
+ /**
+ * Get the last time a special mob received damage.
+ *
+ * @return last damage time as instant.
+ */
+ @Override
+ public Instant lastDamage() {
+ return lastDamage;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/IBloodMob.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/IBloodMob.java
new file mode 100644
index 00000000..733cc05e
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/IBloodMob.java
@@ -0,0 +1,196 @@
+package de.eldoria.bloodnight.bloodmob;
+
+import org.bukkit.entity.Mob;
+import org.bukkit.event.entity.*;
+
+import java.time.Instant;
+import java.util.function.Consumer;
+
+public interface IBloodMob {
+ /**
+ * Called at a fixed amount of ticks while the blood night is active.
+ *
+ * Counting ticks is not a best practice, since the tick speed is not fixed and can be changed.
+ *
+ * Use {@link Instant} to measure time since the last action.
+ */
+ void tick();
+
+ /**
+ * Called when a blood night ends and the special mob is going to be removed in the next step.
+ *
+ * The mob will be removed by the {@link #remove()} method. Therefore this method should not remove the mob.
+ */
+ void onEnd();
+
+ /**
+ * Called when the special mob teleports.
+ *
+ * @param event Event which was dispatched for this mob
+ */
+ void onTeleport(EntityTeleportEvent event);
+
+ /**
+ * Called when the special mob launches a projectile.
+ *
+ * @param event Event which was dispatched for this mob
+ */
+ void onProjectileShoot(ProjectileLaunchEvent event);
+
+ /**
+ * Called when a projectile launched by the special mob hit something.
+ *
+ * @param event Event which was dispatched for this mob
+ */
+ void onProjectileHit(ProjectileHitEvent event);
+
+ /**
+ * Called when the special mob dies.
+ *
+ * @param event The death event of the death of the special mob.
+ */
+ void onDeath(EntityDeathEvent event);
+
+ /**
+ * Called when the special mob kills another entity.
+ *
+ * @param event The death event of the killed entity.
+ */
+ void onKill(EntityDeathEvent event);
+
+ /**
+ * Called when a special mob starts to explode.
+ *
+ * @param event event of the special mob starting to explode
+ */
+ void onExplosionPrimeEvent(ExplosionPrimeEvent event);
+
+ /**
+ * Called when a special mob exploded.
+ *
+ * @param event event of the explosion of the special mob
+ */
+ void onExplosionEvent(EntityExplodeEvent event);
+
+ /**
+ * Called when a special mob changes its target.
+ *
+ * This will only be called, when the new target is of type player or null.
+ *
+ * A special mob will never target something else then a player.
+ *
+ * @param event event containing the new target
+ */
+ void onTargetEvent(EntityTargetEvent event);
+
+ /**
+ * Called when the special mob takes damage
+ *
+ * This is a less specific version of {@link #onDamageByEntity(EntityDamageByEntityEvent)}. Do not implement both.
+ *
+ * @param event damage event of the special mob taking damage
+ */
+ void onDamage(EntityDamageEvent event);
+
+ /**
+ * Called when the entity takes damage from another entity
+ *
+ * This is a more specific version of {@link #onDamage(EntityDamageEvent)}. Do not implement both.
+ *
+ * @param event damage event of the special mob taking damage
+ */
+ void onDamageByEntity(EntityDamageByEntityEvent event);
+
+ /**
+ * Called when the entity damages another entity
+ *
+ * @param event event of the special mob dealing damage
+ */
+ void onHit(EntityDamageByEntityEvent event);
+
+ /**
+ * Attemts to remove the base entity.
+ *
+ * This should not be overridden unless your entity has a extension.
+ *
+ * If you override this just remove the extension and call super afterwards.
+ */
+ void remove();
+
+ /**
+ * This event is called when a entity which is tagged as special mob extension receives damage. This will be most
+ * likely the passenger or the carrier of a special mob.
+ *
+ * This event should be used for damage synchronization.
+ *
+ * Best practise should be that the damage to the extension is forwarded to the base mob.
+ *
+ * Dont implement this if the special mob doesn't has an extension.
+ *
+ * @param event damage event of the extension taking damage,
+ */
+ void onExtensionDamage(EntityDamageEvent event);
+
+ /**
+ * This event is called when a entity which is tagged as special mob extension is killed.
+ *
+ * This will be most likely the passenger or the carrier of a special mob.
+ *
+ * This event should be used to kill the remaining entity.
+ *
+ * Dont implement this if the mob doesn't has an extension.
+ *
+ * @param event damage event of the extension taking damage,
+ */
+ void onExtensionDeath(EntityDeathEvent event);
+
+ /**
+ * Checks if the entity is valid.
+ *
+ * The entity is valid if the base entity is valid.
+ *
+ * @return true when the base entity is valid.
+ */
+ boolean isValid();
+
+ /**
+ * Get the base entity of the mob
+ *
+ * @return base entity
+ */
+ Mob getBase();
+
+ /**
+ * Get the extension of the entity.
+ *
+ * @return the extension or null if {@link #isExtended()} returns false
+ */
+ Mob getExtension();
+
+ /**
+ * Defines that this entity has a extension attached to it.
+ *
+ * @return true if a extension entity is present
+ */
+ boolean isExtended();
+
+ /**
+ * Get the last time a special mob received damage.
+ *
+ * @return last damage time as instant.
+ */
+ Instant lastDamage();
+
+ /**
+ * Invokes a consumer on a extention if {@link #isExtended()} returns true
+ *
+ * @param extension consumer to invoke methods on extention
+ */
+ default void invokeExtension(Consumer extension) {
+ if (isExtended()) {
+ extension.accept(getExtension());
+ }
+ }
+
+
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/Drop.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/Drop.java
new file mode 100644
index 00000000..562a66b4
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/Drop.java
@@ -0,0 +1,81 @@
+package de.eldoria.bloodnight.bloodmob.drop;
+
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.ItemProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import lombok.Getter;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.SerializableAs;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@SerializableAs("bloodNightDrop")
+public class Drop implements ConfigurationSerializable {
+ @ItemProperty(name = "", descr = "")
+ private int itemId;
+ @NumberProperty(name = "", descr = "", max = 64)
+ private int amount;
+ @NumberProperty(name = "", descr = "", max = 100)
+ private int weight;
+
+ public Drop(Map objectMap) {
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ itemId = map.getValue("itemId");
+ amount = map.getValue("amount");
+ weight = map.getValue("weight");
+ }
+
+ public Drop(int itemId, int amount, int weight) {
+ this.itemId = itemId;
+ this.amount = amount;
+ this.weight = weight;
+ }
+
+ public Drop() {
+ }
+
+ @Override
+ public @NotNull
+ Map serialize() {
+ return SerializationUtil.newBuilder()
+ .add("item", itemId)
+ .add("amount", amount)
+ .add("weight", weight)
+ .build();
+ }
+
+ public int amount() {
+ return amount;
+ }
+
+ public int itemId() {
+ return itemId;
+ }
+
+ public int weight() {
+ return weight;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Drop drop = (Drop) o;
+
+ if (itemId != drop.itemId) return false;
+ if (amount != drop.amount) return false;
+ return weight == drop.weight;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = itemId;
+ result = 31 * result + amount;
+ result = 31 * result + weight;
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/IDrop.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/IDrop.java
new file mode 100644
index 00000000..2e630a4a
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/drop/IDrop.java
@@ -0,0 +1,7 @@
+package de.eldoria.bloodnight.bloodmob.drop;
+
+public interface IDrop {
+ int getItemId();
+
+ int getWeight();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/ClassesProvider.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/ClassesProvider.java
new file mode 100644
index 00000000..2cb95f56
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/ClassesProvider.java
@@ -0,0 +1,10 @@
+package de.eldoria.bloodnight.bloodmob.node;
+
+import java.util.Set;
+
+public interface ClassesProvider {
+ default Set> getClasses(Set> set){
+ set.add(getClass());
+ return set;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/Node.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/Node.java
new file mode 100644
index 00000000..4b21db81
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/Node.java
@@ -0,0 +1,38 @@
+package de.eldoria.bloodnight.bloodmob.node;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+
+import java.util.Set;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public interface Node extends ConfigurationSerializable, ClassesProvider {
+ void handle(IBloodMob mob, ContextContainer context);
+
+ default ContextContainer getTransformedOutput(ContextContainer context) {
+ return context;
+ }
+
+ @Override
+ default Set> getClasses(Set> set) {
+ set.add(getClass());
+ return set;
+ }
+
+ default void removeLast() {
+ }
+
+ default boolean isLast() {
+ return true;
+ }
+
+ default boolean addNode(Node node) {
+ return false;
+ }
+
+ default Node getLast() {
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/NodeHolder.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/NodeHolder.java
new file mode 100644
index 00000000..b2bcaddb
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/NodeHolder.java
@@ -0,0 +1,89 @@
+package de.eldoria.bloodnight.bloodmob.node;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.Set;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public abstract class NodeHolder implements Node, ConfigurationSerializable {
+ @Nullable
+ @Property(name = "", descr = "")
+ private Node nextNode;
+
+ public NodeHolder(Node nextNode) {
+ this.nextNode = nextNode;
+ }
+
+ public NodeHolder() {
+ }
+
+ @Nullable
+ public Node nextNode() {
+ return nextNode;
+ }
+
+ public void nextNode(Node nextNode) {
+ this.nextNode = nextNode;
+ }
+
+ public NodeHolder(Map objectMap) {
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ nextNode = map.getValue("node");
+ }
+
+ @Override
+ @NotNull
+ public Map serialize() {
+ return SerializationUtil.newBuilder()
+ .add("node", nextNode)
+ .build();
+ }
+
+ @Override
+ public ContextContainer getTransformedOutput(ContextContainer context) {
+ return nextNode == null ? context : nextNode.getTransformedOutput(context);
+ }
+
+ @Override
+ public Set> getClasses(Set> set) {
+ Node.super.getClasses(set);
+ return nextNode != null ? nextNode.getClasses(set) : set;
+ }
+
+ @Override
+ public void removeLast() {
+ if (nextNode != null && nextNode.isLast()) {
+ nextNode = null;
+ }
+ }
+
+ @Override
+ public boolean isLast() {
+ return nextNode == null;
+ }
+
+ @Override
+ public boolean addNode(Node node) {
+ if (nextNode != null) {
+ return nextNode.addNode(node);
+ }
+ nextNode = node;
+ return true;
+ }
+
+ @Override
+ public Node getLast() {
+ if (isLast()) {
+ return this;
+ }
+ return nextNode.getLast();
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/annotations/RequiresContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/annotations/RequiresContext.java
new file mode 100644
index 00000000..ab98c427
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/annotations/RequiresContext.java
@@ -0,0 +1,14 @@
+package de.eldoria.bloodnight.bloodmob.node.annotations;
+
+import de.eldoria.bloodnight.bloodmob.node.context.IContext;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RequiresContext {
+ Class extends IContext>[] value() default {};
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ICancelableContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ICancelableContext.java
new file mode 100644
index 00000000..625ea6a4
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ICancelableContext.java
@@ -0,0 +1,11 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.event.Cancellable;
+
+public interface ICancelableContext extends IContext {
+ static ICancelableContext of(Cancellable event) {
+ return () -> event;
+ }
+
+ Cancellable getCancelable();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IContext.java
new file mode 100644
index 00000000..c974bfef
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IContext.java
@@ -0,0 +1,4 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+public interface IContext {
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IDamageCauseContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IDamageCauseContext.java
new file mode 100644
index 00000000..d53dc4ab
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IDamageCauseContext.java
@@ -0,0 +1,11 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+
+public interface IDamageCauseContext extends IContext {
+ static IDamageCauseContext of(DamageCause cause) {
+ return () -> cause;
+ }
+
+ DamageCause getDamageCause();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityContext.java
new file mode 100644
index 00000000..4a6f1b00
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityContext.java
@@ -0,0 +1,11 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.entity.Entity;
+
+public interface IEntityContext extends IContext {
+ static IEntityContext of(Entity entity) {
+ return () -> entity;
+ }
+
+ Entity getEntity();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityInteraction.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityInteraction.java
new file mode 100644
index 00000000..cd2615d9
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IEntityInteraction.java
@@ -0,0 +1,23 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.entity.Entity;
+
+public interface IEntityInteraction extends IContext {
+ static IEntityInteraction of(Entity actor, Entity target) {
+ return new IEntityInteraction() {
+ @Override
+ public Entity getActor() {
+ return actor;
+ }
+
+ @Override
+ public Entity getTarget() {
+ return target;
+ }
+ };
+ }
+
+ Entity getActor();
+
+ Entity getTarget();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityContext.java
new file mode 100644
index 00000000..e50f3d44
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityContext.java
@@ -0,0 +1,16 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+
+public interface ILivingEntityContext extends IEntityContext {
+ static ILivingEntityContext of(LivingEntity entity) {
+ return () -> entity;
+ }
+
+ static ILivingEntityContext of(Entity entity) {
+ return () -> (LivingEntity) entity;
+ }
+
+ LivingEntity getEntity();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityInteraction.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityInteraction.java
new file mode 100644
index 00000000..3049e5e9
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILivingEntityInteraction.java
@@ -0,0 +1,30 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+
+public interface ILivingEntityInteraction extends IEntityInteraction {
+ static ILivingEntityInteraction of(LivingEntity actor, LivingEntity target) {
+ return new ILivingEntityInteraction() {
+ @Override
+ public LivingEntity getActor() {
+ return actor;
+ }
+
+ @Override
+ public LivingEntity getTarget() {
+ return target;
+ }
+ };
+ }
+
+ static ILivingEntityInteraction of(Entity actor, Entity target) {
+ return of((LivingEntity) actor, (LivingEntity) target);
+ }
+
+ @Override
+ LivingEntity getActor();
+
+ @Override
+ LivingEntity getTarget();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILocationContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILocationContext.java
new file mode 100644
index 00000000..487a8091
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/ILocationContext.java
@@ -0,0 +1,11 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.Location;
+
+public interface ILocationContext extends IContext {
+ static ILocationContext of(Location location) {
+ return () -> location;
+ }
+
+ Location getLocation();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IMoveContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IMoveContext.java
new file mode 100644
index 00000000..4d04be02
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IMoveContext.java
@@ -0,0 +1,21 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.Location;
+
+public interface IMoveContext extends ILocationContext {
+ static IMoveContext of(Location from, Location to) {
+ return new IMoveContext() {
+ @Override
+ public Location getNewLocation() {
+ return to;
+ }
+
+ @Override
+ public Location getLocation() {
+ return from;
+ }
+ } ;
+ }
+
+ Location getNewLocation();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IPlayerContext.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IPlayerContext.java
new file mode 100644
index 00000000..1f52b41f
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IPlayerContext.java
@@ -0,0 +1,12 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import org.bukkit.entity.Player;
+
+public interface IPlayerContext extends ILivingEntityContext{
+ static IPlayerContext of(Player player) {
+ return () -> player;
+ }
+
+ @Override
+ Player getEntity();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IllegalContextException.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IllegalContextException.java
new file mode 100644
index 00000000..fea20331
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/context/IllegalContextException.java
@@ -0,0 +1,9 @@
+package de.eldoria.bloodnight.bloodmob.node.context;
+
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+
+public class IllegalContextException extends RuntimeException {
+ public IllegalContextException(ContextType type, IContext context) {
+ super("Class " + context.getClass().getSimpleName() + " can not be assigned to type " + type);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainer.java
new file mode 100644
index 00000000..f8dc0275
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainer.java
@@ -0,0 +1,166 @@
+package de.eldoria.bloodnight.bloodmob.node.contextcontainer;
+
+import de.eldoria.bloodnight.bloodmob.node.context.IContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IllegalContextException;
+import de.eldoria.bloodnight.bloodmob.registry.items.ItemRegistry;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ContextContainer {
+ private ItemRegistry itemRegistry;
+ private final Map, ContextData> contextMap;
+
+ private ContextContainer(Map, ContextData> contextMap) {
+ this.contextMap = contextMap;
+ }
+
+ /**
+ * Get the context of the requested type.
+ *
+ * @param type context type
+ * @param type of context
+ * @return optional holding the context is present
+ */
+ @SuppressWarnings("unchecked")
+ public Optional get(ContextType type) {
+ return Optional.ofNullable((T) contextMap.get(type.contextClazz()));
+ }
+
+ /**
+ * Checks if the context has this type of context
+ *
+ * @param type type of context
+ * @return true if context is present
+ */
+ public boolean has(ContextType> type) {
+ return contextMap.containsKey(type.contextClazz());
+ }
+
+ /**
+ * Transform the target context to another context.
+ *
+ * The target context will be removed from the contexts and the result context will be added.
+ *
+ * The method will have no effect if {@link #has(ContextType)} returns false for target.
+ *
+ * @param type of target
+ * @param type of result
+ * @param target target context
+ * @param result result context
+ * @param map map target to result
+ * @param descr
+ */
+ public void transform(ContextType target, ContextType result, Function map, String descr) {
+ get(target).ifPresent(t -> {
+ add(result, map.apply(t), descr);
+ remove(target);
+ });
+ }
+
+ /**
+ * Add a context to the context Container.
+ *
+ * @param type type of context type
+ * @param context context matching the {@link ContextType#contextClazz()}
+ * @throws IllegalContextException if the {@link ContextType#contextClazz()} does not match the {@link IContext}
+ */
+ public void add(ContextType type, T context, String descr) {
+ if (context.getClass().isInstance(type.contextClazz())) {
+ contextMap.put(type.contextClazz(), ContextData.of(context, descr));
+ return;
+ }
+ throw new IllegalContextException(type, context);
+ }
+
+ /**
+ * Remove a context from the container
+ *
+ * @param type context type
+ */
+ public void remove(ContextType> type) {
+ contextMap.remove(type.contextClazz());
+ }
+
+ public Collection> getTypes() {
+ return contextMap.keySet().stream().map(ContextType::getType).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
+ }
+
+ /**
+ * Get a builder.
+ *
+ * @return new builder instance;
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builder(Map, ContextData> contextMap) {
+ return new Builder(contextMap);
+ }
+
+ public static Builder builder(ContextContainer context) {
+ return builder(new HashMap<>(context.contextMap));
+ }
+
+ public static ContextContainer of(ContextType type, T context, String descr) {
+ return builder().add(type, context, descr).build();
+ }
+
+ public static Builder builder(ContextType type, T context, String descr) {
+ return builder().add(type, context, descr);
+ }
+
+ public ItemRegistry itemRegistry() {
+ return itemRegistry;
+ }
+
+ public static class Builder {
+ private final Map, ContextData> contextMap;
+
+ public Builder(Map, ContextData> contextMap) {
+ this.contextMap = contextMap;
+ }
+
+ public Builder() {
+ contextMap = new HashMap<>();
+ }
+
+ /**
+ * Add a context to the context Container.
+ *
+ * @param type type of context type
+ * @param context context matching the {@link ContextType#contextClazz()}
+ * @return builder instance;
+ * @throws IllegalContextException if the {@link ContextType#contextClazz()} does not match the {@link IContext}
+ */
+ public Builder add(ContextType type, T context, String descr) {
+ if (context.getClass().isInstance(type.contextClazz())) {
+ contextMap.put(type.contextClazz(), ContextData.of(context, descr));
+ return this;
+ }
+ throw new IllegalContextException(type, context);
+ }
+
+ public ContextContainer build() {
+ return new ContextContainer(contextMap);
+ }
+ }
+
+ /**
+ * Get a new instance of this object with the same values
+ *
+ * @return new instance with same values
+ */
+ public ContextContainer copy() {
+ return new ContextContainer(new HashMap<>(contextMap));
+ }
+
+ public boolean contains(Class> clazz) {
+ return contextMap.containsKey(clazz);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainerFactory.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainerFactory.java
new file mode 100644
index 00000000..2ecefda0
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextContainerFactory.java
@@ -0,0 +1,140 @@
+package de.eldoria.bloodnight.bloodmob.node.contextcontainer;
+
+import de.eldoria.bloodnight.bloodmob.node.context.ICancelableContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IDamageCauseContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IEntityContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ILivingEntityContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ILocationContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IMoveContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IPlayerContext;
+import de.eldoria.bloodnight.bloodmob.settings.BehaviourNodeType;
+import de.eldoria.eldoutilities.entityutils.ProjectileSender;
+import de.eldoria.eldoutilities.entityutils.ProjectileUtil;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.event.entity.EntityExplodeEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.EntityTeleportEvent;
+import org.bukkit.event.entity.ExplosionPrimeEvent;
+import org.bukkit.event.entity.ProjectileHitEvent;
+import org.bukkit.event.entity.ProjectileLaunchEvent;
+
+public class ContextContainerFactory {
+ public static ContextContainer ofTick() {
+ return ContextContainer.builder().build();
+ }
+
+ public static ContextContainer ofOnEnd() {
+ return ContextContainer.builder().build();
+ }
+
+ public static ContextContainer ofOnTeleport(EntityTeleportEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.MOVE, IMoveContext.of(event.getFrom(), event.getTo()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnProjectileShoot(ProjectileLaunchEvent event) {
+ ProjectileSender projectileSource = ProjectileUtil.getProjectileSource(event.getEntity());
+ return ofCancelable(event)
+ .add(ContextType.ENTITY, IEntityContext.of(event.getEntity()), "")
+ .add(ContextType.LOCATION, ILocationContext.of(event.getLocation()), "")
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of((LivingEntity) projectileSource.getEntity()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnProjectileHit(ProjectileHitEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.ENTITY, IEntityContext.of(event.getEntity()), "")
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of((LivingEntity) event.getHitEntity()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnDeath(EntityDeathEvent event) {
+ return ContextContainer.builder()
+ .add(ContextType.PLAYER, IPlayerContext.of(event.getEntity().getKiller()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnKill(EntityDeathEvent event) {
+ return ContextContainer.builder()
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of(event.getEntity()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnExplosionPrime(ExplosionPrimeEvent event) {
+ return ofCancelable(event).build();
+ }
+
+ public static ContextContainer ofOnExplosion(EntityExplodeEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.LOCATION, ILocationContext.of(event.getLocation()), "")
+ .add(ContextType.ENTITY, IEntityContext.of(event.getEntity()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnTarget(EntityTargetEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of((LivingEntity) event.getTarget()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnDamage(EntityDamageEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.DAMAGE_CAUSE, IDamageCauseContext.of(event.getCause()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnDamageByEntity(EntityDamageByEntityEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.DAMAGE_CAUSE, IDamageCauseContext.of(event.getCause()), "")
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of(event.getDamager()), "")
+ .build();
+ }
+
+ public static ContextContainer ofOnHit(EntityDamageByEntityEvent event) {
+ return ofCancelable(event)
+ .add(ContextType.LIVING_ENTITY, ILivingEntityContext.of(event.getEntity()), "")
+ .build();
+ }
+
+ private static ContextContainer.Builder ofCancelable(Cancellable cancellable) {
+ return ContextContainer.builder(ContextType.CANCELABLE, ICancelableContext.of(cancellable), "");
+ }
+
+ public static ContextContainer mock(BehaviourNodeType type) {
+ switch (type) {
+ case TICK:
+ return ofTick();
+ case ON_END:
+ return ofOnEnd();
+ case ON_TELEPORT:
+ return ofOnTeleport(new EntityTeleportEvent(null, null, null));
+ case ON_PROJECTILE_SHOOT:
+ return ofOnProjectileShoot(new ProjectileLaunchEvent(null));
+ case ON_PROJECTILE_HIT:
+ return ofOnProjectileHit(new ProjectileHitEvent(null));
+ case ON_DEATH:
+ return ofOnDeath(new EntityDeathEvent(null, null));
+ case ON_KILL:
+ return ofOnKill(new EntityDeathEvent(null, null));
+ case ON_EXPLOSION_PRIME:
+ return ofOnExplosionPrime(new ExplosionPrimeEvent(null));
+ case ON_EXPLOSION:
+ return ofOnExplosion(new EntityExplodeEvent(null, null, null, 0));
+ case ON_TARGET:
+ return ofOnTarget(new EntityTargetEvent(null, null, null));
+ case ON_DAMAGE:
+ return ofOnDamage(new EntityDamageByEntityEvent(null, null, null, 0));
+ case ON_DAMAGE_BY_ENTITY:
+ return ofOnDamageByEntity(new EntityDamageByEntityEvent(null, null, null, 0));
+ case ON_HIT:
+ return ofOnHit(new EntityDamageByEntityEvent(null, null, null, 0));
+ default:
+ throw new IllegalStateException("Unexpected value: " + type);
+ }
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextData.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextData.java
new file mode 100644
index 00000000..053c0899
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextData.java
@@ -0,0 +1,25 @@
+package de.eldoria.bloodnight.bloodmob.node.contextcontainer;
+
+import de.eldoria.bloodnight.bloodmob.node.context.IContext;
+
+public class ContextData {
+ IContext context;
+ String descr;
+
+ public static ContextData of(IContext context, String descr) {
+ return new ContextData(context, descr);
+ }
+
+ private ContextData(IContext context, String descr) {
+ this.context = context;
+ this.descr = descr;
+ }
+
+ public IContext context() {
+ return context;
+ }
+
+ public String descr() {
+ return descr;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextType.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextType.java
new file mode 100644
index 00000000..bdefb98e
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/contextcontainer/ContextType.java
@@ -0,0 +1,81 @@
+package de.eldoria.bloodnight.bloodmob.node.contextcontainer;
+
+import de.eldoria.bloodnight.bloodmob.node.context.*;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityEvent;
+import org.bukkit.event.entity.EntityTeleportEvent;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.vehicle.VehicleMoveEvent;
+
+import java.util.Optional;
+
+public interface ContextType {
+ /**
+ * A context which provides a {@link Cancellable} state to change.
+ */
+ ContextType CANCELABLE = of(ICancelableContext.class);
+
+ /**
+ * A context which provides a {@link DamageCause} of a {@link EntityDamageEvent}
+ */
+ ContextType DAMAGE_CAUSE = of(IDamageCauseContext.class);
+
+ /**
+ * A context which provides a {@link Entity} from an {@link EntityEvent}
+ */
+ ContextType ENTITY = of(IEntityContext.class);
+
+ /**
+ * A context which provides a {@link Entity} from an {@link EntityEvent}.
+ * This entity will always be of type {@link LivingEntity}.
+ */
+ ContextType LIVING_ENTITY = of(ILivingEntityContext.class);
+
+ /**
+ * A context which provides a {@link Location} from events like {@link EntityTeleportEvent}, {@link PlayerMoveEvent},
+ * {@link VehicleMoveEvent}, {@link }.
+ * Can also wrap things like {@link Player#getLocation()}.
+ */
+ ContextType LOCATION = of(ILocationContext.class);
+
+ /**
+ * A context which provides information from event like {@link EntityTeleportEvent}, {@link PlayerMoveEvent}.
+ */
+ ContextType MOVE = of(IMoveContext.class);
+
+ /**
+ * A context which provides information from {@link PlayerEvent}.
+ */
+ ContextType PLAYER = of(IPlayerContext.class);
+
+ static ContextType of(Class clazz) {
+ return () -> clazz;
+ }
+
+ /**
+ * Returns the class of the context.
+ *
+ * @return class of {@link IContext}
+ */
+ Class contextClazz();
+
+ static ContextType>[] values() {
+ return new ContextType[]{CANCELABLE, DAMAGE_CAUSE, ENTITY, LIVING_ENTITY, LOCATION, MOVE, PLAYER};
+ }
+
+ static Optional> getType(Class extends IContext> context) {
+ for (ContextType> value : values()) {
+ if (value.contextClazz() == context) {
+ return Optional.of(value);
+ }
+ }
+ return Optional.empty();
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/effect/EffectNode.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/effect/EffectNode.java
new file mode 100644
index 00000000..6087663a
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/effect/EffectNode.java
@@ -0,0 +1,16 @@
+package de.eldoria.bloodnight.bloodmob.node.effect;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import org.bukkit.entity.LivingEntity;
+
+public interface EffectNode extends Node {
+
+ @Override
+ default void handle(IBloodMob mob, ContextContainer context) {
+ apply(mob.getBase());
+ }
+
+ void apply(LivingEntity entity);
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/filter/FilterNode.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/filter/FilterNode.java
new file mode 100644
index 00000000..94d56025
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/filter/FilterNode.java
@@ -0,0 +1,31 @@
+package de.eldoria.bloodnight.bloodmob.node.filter;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.NodeHolder;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public abstract class FilterNode extends NodeHolder {
+ public FilterNode(Node node) {
+ super(node);
+ }
+
+ public FilterNode(Map objectMap) {
+ super(objectMap);
+ }
+
+ public FilterNode() {
+ }
+
+ public abstract boolean check(IBloodMob mob, ContextContainer context);
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ if (check(mob, context) && nextNode() != null) nextNode().handle(mob, context);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/mapper/MapperNode.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/mapper/MapperNode.java
new file mode 100644
index 00000000..fa7eaff2
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/mapper/MapperNode.java
@@ -0,0 +1,36 @@
+package de.eldoria.bloodnight.bloodmob.node.mapper;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.NodeHolder;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+/**
+ * Instance to map context to another
+ */
+@NoArgsConstructor
+public abstract class MapperNode extends NodeHolder {
+ public MapperNode(Node node) {
+ super(node);
+ }
+
+ public MapperNode(Map objectMap) {
+ super(objectMap);
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ map(context);
+ if (nextNode() != null) nextNode().handle(mob, context);
+ }
+
+ /**
+ * Change the provided context to your preference.
+ *
+ * @param context context
+ */
+ public abstract void map(ContextContainer context);
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/predicate/PredicateNode.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/predicate/PredicateNode.java
new file mode 100644
index 00000000..2eae6bb1
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/node/predicate/PredicateNode.java
@@ -0,0 +1,12 @@
+package de.eldoria.bloodnight.bloodmob.node.predicate;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.ClassesProvider;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public interface PredicateNode extends ConfigurationSerializable, ClassesProvider {
+ boolean test(IBloodMob mob, ContextContainer context);
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/ApplyDamage.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/ApplyDamage.java
new file mode 100644
index 00000000..5633b5c8
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/ApplyDamage.java
@@ -0,0 +1,46 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ILivingEntityContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import lombok.NoArgsConstructor;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeInstance;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+@RequiresContext(ILivingEntityContext.class)
+@Property(name = "", descr = "")
+public class ApplyDamage implements Node {
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ context.get(ContextType.LIVING_ENTITY).ifPresent(entity -> {
+ AttributeInstance attribute = mob.getBase().getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
+ entity.getEntity().damage(attribute.getValue(), mob.getBase());
+ });
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ return obj.getClass() == getClass();
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/CancelEvent.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/CancelEvent.java
new file mode 100644
index 00000000..285abbae
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/CancelEvent.java
@@ -0,0 +1,47 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ICancelableContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import lombok.NoArgsConstructor;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+@RequiresContext(ICancelableContext.class)
+public class CancelEvent implements Node {
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ context.get(ContextType.CANCELABLE).ifPresent(c -> c.getCancelable().setCancelled(true));
+ }
+
+ /**
+ * Creates a Map representation of this class.
+ *
+ * This class must provide a method to restore this class, as defined in
+ * the {@link ConfigurationSerializable} interface javadocs.
+ *
+ * @return Map containing the current state of this class
+ */
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ return obj.getClass() == getClass();
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/LaunchProjectileOnTarget.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/LaunchProjectileOnTarget.java
new file mode 100644
index 00000000..109d0802
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/LaunchProjectileOnTarget.java
@@ -0,0 +1,83 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumericProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.entity.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class LaunchProjectileOnTarget implements Node {
+
+ @Property(name = "", descr = "")
+ ProjectileType projectileType;
+ @NumericProperty(name = "", descr = "", max = 64)
+ float speed;
+
+ public LaunchProjectileOnTarget(ProjectileType projectileType, float speed) {
+ this.projectileType = projectileType;
+ this.speed = speed;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ BloodMobUtil.launchProjectileOnTarget(mob.getBase(), projectileType.projectileClazz(), speed);
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ public enum ProjectileType {
+ ARROW(Arrow.class),
+ DRAGON_FIREBALL(DragonFireball.class),
+ EGG(Egg.class),
+ ENDER_PEARL(EnderPearl.class),
+ FIREBALL(Fireball.class),
+ FISH_HOOK(FishHook.class),
+ LARGE_FIREBALL(LargeFireball.class),
+ LLAMA_SPIT(LlamaSpit.class),
+ SHULKER_BULLET(ShulkerBullet.class),
+ SIZED_FIREBALL(SizedFireball.class),
+ SMALL_FIREBALL(SmallFireball.class),
+ SNOWBALL(Snowball.class),
+ WITHER_SKULL(WitherSkull.class);
+
+ private final Class extends Projectile> projectileClazz;
+
+ ProjectileType(Class extends Projectile> projectileClazz) {
+ this.projectileClazz = projectileClazz;
+ }
+
+ public Class extends Projectile> projectileClazz() {
+ return projectileClazz;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LaunchProjectileOnTarget that = (LaunchProjectileOnTarget) o;
+
+ if (Float.compare(that.speed, speed) != 0) return false;
+ return projectileType == that.projectileType;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = projectileType.hashCode();
+ result = 31 * result + (speed != +0.0f ? Float.floatToIntBits(speed) : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/OtherPotion.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/OtherPotion.java
new file mode 100644
index 00000000..88bbbd0d
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/OtherPotion.java
@@ -0,0 +1,75 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ILivingEntityContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.EnumLikeProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumericProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import lombok.NoArgsConstructor;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * Applies a potion to itself
+ */
+@NoArgsConstructor
+@RequiresContext(ILivingEntityContext.class)
+public class OtherPotion implements Node {
+ @EnumLikeProperty(name = "", descr = "")
+ private PotionEffectType type;
+ @NumberProperty(name = "", descr = "")
+ private int seconds;
+ @NumericProperty(name = "", descr = "")
+ private int amplifier;
+ @Property(name = "", descr = "")
+ private boolean visible;
+
+ public OtherPotion(PotionEffectType type, int seconds, int amplifier, boolean visible) {
+ this.type = type;
+ this.seconds = seconds;
+ this.amplifier = amplifier;
+ this.visible = visible;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ context.get(ContextType.LIVING_ENTITY).ifPresent(entity -> entity.getEntity()
+ .addPotionEffect(new PotionEffect(type, seconds * 20, amplifier, false, visible)));
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ OtherPotion that = (OtherPotion) o;
+
+ if (seconds != that.seconds) return false;
+ if (amplifier != that.amplifier) return false;
+ if (visible != that.visible) return false;
+ return type.equals(that.type);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type.hashCode();
+ result = 31 * result + seconds;
+ result = 31 * result + amplifier;
+ result = 31 * result + (visible ? 1 : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/PotionCloudAction.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/PotionCloudAction.java
new file mode 100644
index 00000000..4925c9ad
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/PotionCloudAction.java
@@ -0,0 +1,94 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.ILocationContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.PotionCloud;
+import lombok.NoArgsConstructor;
+import org.bukkit.Color;
+import org.bukkit.potion.PotionData;
+import org.bukkit.potion.PotionType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+@RequiresContext(ILocationContext.class)
+public class PotionCloudAction implements Node {
+ @Property(name = "", descr = "")
+ boolean extended;
+ @Property(name = "", descr = "")
+ private Color color;
+ @NumberProperty(name = "", descr = "", max = 60)
+ private int duration;
+ @NumberProperty(name = "", descr = "", max = 60)
+ private int radius;
+ @NumberProperty(name = "", descr = "", max = 50)
+ private int growth;
+ @Property(name = "", descr = "")
+ private PotionType potionType;
+ @Property(name = "", descr = "")
+ private boolean upgraded;
+
+ public PotionCloudAction(boolean extended, Color color, int duration, int radius, int growth, PotionType potionType, boolean upgraded) {
+ this.extended = extended;
+ this.color = color;
+ this.duration = duration;
+ this.radius = radius;
+ this.growth = growth;
+ this.potionType = potionType;
+ this.upgraded = upgraded;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ context.get(ContextType.LOCATION).ifPresent(location -> {
+ PotionCloud.builder(location.getLocation().subtract(0, 1, 0))
+ .fromSource(mob.getBase())
+ .setDuration(duration)
+ .withRadius(4)
+ .setRadiusPerTick(growth / 100f)
+ .ofColor(color)
+ .setPotionType(new PotionData(potionType, extended, upgraded));
+ });
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PotionCloudAction that = (PotionCloudAction) o;
+
+ if (extended != that.extended) return false;
+ if (duration != that.duration) return false;
+ if (radius != that.radius) return false;
+ if (growth != that.growth) return false;
+ if (upgraded != that.upgraded) return false;
+ if (!color.equals(that.color)) return false;
+ return potionType == that.potionType;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (extended ? 1 : 0);
+ result = 31 * result + color.hashCode();
+ result = 31 * result + duration;
+ result = 31 * result + radius;
+ result = 31 * result + growth;
+ result = 31 * result + potionType.hashCode();
+ result = 31 * result + (upgraded ? 1 : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/RemoveSelfPotion.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/RemoveSelfPotion.java
new file mode 100644
index 00000000..e8282f0c
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/RemoveSelfPotion.java
@@ -0,0 +1,63 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.EnumLikeProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import lombok.NoArgsConstructor;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * Applies a potion to itself
+ */
+@NoArgsConstructor
+public class RemoveSelfPotion implements Node {
+ @EnumLikeProperty(name = "", descr = "")
+ private PotionEffectType type;
+ @Property(name = "", descr = "")
+ private boolean base;
+ @Property(name = "", descr = "")
+ private boolean extension;
+
+ public RemoveSelfPotion(PotionEffectType type, boolean base, boolean extension) {
+ this.type = type;
+ this.base = base;
+ this.extension = extension;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ if (base) mob.getBase().removePotionEffect(type);
+ if (extension) mob.invokeExtension(m -> m.removePotionEffect(type));
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RemoveSelfPotion that = (RemoveSelfPotion) o;
+
+ if (base != that.base) return false;
+ if (extension != that.extension) return false;
+ return type != null ? type.equals(that.type) : that.type == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (base ? 1 : 0);
+ result = 31 * result + (extension ? 1 : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SearchNearPlayerTarget.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SearchNearPlayerTarget.java
new file mode 100644
index 00000000..ce3052ec
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SearchNearPlayerTarget.java
@@ -0,0 +1,67 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import lombok.NoArgsConstructor;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+@NoArgsConstructor
+public class SearchNearPlayerTarget implements Node {
+ @NumberProperty(name = "", descr = "", max = 128)
+ private int range;
+
+ public SearchNearPlayerTarget(int range) {
+ this.range = range;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ Location loc = mob.getBase().getLocation();
+ Collection nearbyPlayers = loc.getWorld().
+ getNearbyEntities(loc, range, range, range, entity -> {
+ if (entity.getType() == EntityType.PLAYER) {
+ Player player = (Player) entity;
+ return !player.isInvisible() && (player.getGameMode() == GameMode.SURVIVAL || player.getGameMode() == GameMode.CREATIVE);
+ }
+ return false;
+ });
+ if (nearbyPlayers.isEmpty()) {
+ return;
+ }
+ mob.getBase().setTarget((LivingEntity) new ArrayList<>(nearbyPlayers).get(0));
+ mob.invokeExtension(e -> e.setTarget((LivingEntity) new ArrayList<>(nearbyPlayers).get(0)));
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SearchNearPlayerTarget that = (SearchNearPlayerTarget) o;
+
+ return range == that.range;
+ }
+
+ @Override
+ public int hashCode() {
+ return range;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SelfPotion.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SelfPotion.java
new file mode 100644
index 00000000..bea31eeb
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SelfPotion.java
@@ -0,0 +1,80 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.EnumLikeProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * Applies a potion to itself
+ */
+@NoArgsConstructor
+public class SelfPotion implements Node {
+ @EnumLikeProperty(name = "", descr = "")
+ private PotionEffectType type;
+ @NumberProperty(name = "", descr = "")
+ private int seconds;
+ @NumberProperty(name = "", descr = "")
+ private int amplifier;
+ @Property(name = "", descr = "")
+ private boolean visible;
+ @Property(name = "", descr = "")
+ private boolean extension;
+ @Property(name = "", descr = "")
+ private boolean base;
+
+ public SelfPotion(PotionEffectType type, int seconds, int amplifier, boolean visible, boolean extension, boolean base) {
+ this.type = type;
+ this.seconds = seconds;
+ this.amplifier = amplifier;
+ this.visible = visible;
+ this.extension = extension;
+ this.base = base;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ if (base) BloodMobUtil.addPotionEffect(mob.getBase(), type, amplifier, visible);
+ if (extension) mob.invokeExtension(m -> BloodMobUtil.addPotionEffect(m, type, seconds, amplifier, visible));
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SelfPotion that = (SelfPotion) o;
+
+ if (seconds != that.seconds) return false;
+ if (amplifier != that.amplifier) return false;
+ if (visible != that.visible) return false;
+ if (extension != that.extension) return false;
+ if (base != that.base) return false;
+ return type != null ? type.equals(that.type) : that.type == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + seconds;
+ result = 31 * result + amplifier;
+ result = 31 * result + (visible ? 1 : 0);
+ result = 31 * result + (extension ? 1 : 0);
+ result = 31 * result + (base ? 1 : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SetEquipment.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SetEquipment.java
new file mode 100644
index 00000000..a274599a
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/SetEquipment.java
@@ -0,0 +1,56 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.settings.Equipment;
+import lombok.NoArgsConstructor;
+import org.bukkit.entity.Mob;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class SetEquipment implements Node {
+ @Property(name = "", descr = "")
+ private boolean extension = false;
+ @Property(name = "", descr = "")
+ private Equipment equipment;
+
+ public SetEquipment(boolean extension, Equipment equipment) {
+ this.extension = extension;
+ this.equipment = equipment;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ Mob currMob = extension ? mob.getExtension() : mob.getBase();
+ if (currMob == null) return;
+ equipment.apply(currMob, context.itemRegistry());
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SetEquipment that = (SetEquipment) o;
+
+ if (extension != that.extension) return false;
+ return equipment != null ? equipment.equals(that.equipment) : that.equipment == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (extension ? 1 : 0);
+ result = 31 * result + (equipment != null ? equipment.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/TeleportToTarget.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/TeleportToTarget.java
new file mode 100644
index 00000000..1634ae1e
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/action/TeleportToTarget.java
@@ -0,0 +1,90 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.action;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.EntityEffect;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.block.Block;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+
+@NoArgsConstructor
+public class TeleportToTarget implements Node {
+ private static final int MAX_DIST_SQRT = 40000;
+ private static final int MIN_DIST_SQRT = 25;
+ @Property(name = "", descr = "")
+ private Particle particle;
+ @Property(name = "", descr = "")
+ private EntityEffect effect;
+
+ public TeleportToTarget(Particle particle, EntityEffect effect) {
+ this.particle = particle;
+ this.effect = effect;
+ }
+
+ @Override
+ public void handle(IBloodMob mob, ContextContainer context) {
+ LivingEntity target = mob.getBase().getTarget();
+
+ if (target == null) return;
+
+ double distSqrt = target.getLocation().distanceSquared(mob.getBase().getLocation());
+
+ if (distSqrt > MIN_DIST_SQRT && distSqrt > MAX_DIST_SQRT) {
+ Location loc = target.getLocation();
+ ThreadLocalRandom rand = ThreadLocalRandom.current();
+
+ // find a fuzzy target around.
+ Vector fuzz = new Vector(rand.nextDouble(-2, 2), 0, rand.nextDouble(-2, 2));
+ Block first = loc.getWorld().getBlockAt(loc.add(fuzz));
+ Block second = first.getRelative(0, 1, 0);
+
+ Location targetLoc;
+ // check if there is space
+ if (first.getType() == Material.AIR && second.getType() == Material.AIR) {
+ targetLoc = first.getLocation();
+ } else {
+ // if teleport wasn't successful for some time we teleport to the target directly.
+ targetLoc = target.getLocation();
+ }
+
+ mob.getBase().teleport(targetLoc);
+ if (particle != null) BloodMobUtil.spawnParticlesAround(loc, particle, 10);
+ if (effect != null) mob.getBase().playEffect(effect);
+ }
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TeleportToTarget that = (TeleportToTarget) o;
+
+ if (particle != that.particle) return false;
+ return effect == that.effect;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = particle != null ? particle.hashCode() : 0;
+ result = 31 * result + (effect != null ? effect.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/DustParticleEffect.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/DustParticleEffect.java
new file mode 100644
index 00000000..ba61c4b7
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/DustParticleEffect.java
@@ -0,0 +1,62 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.effect;
+
+import de.eldoria.bloodnight.bloodmob.node.effect.EffectNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumericProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.Color;
+import org.bukkit.Particle;
+import org.bukkit.entity.LivingEntity;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class DustParticleEffect implements EffectNode {
+ @Property(name = "", descr = "")
+ Color color;
+ @NumberProperty(name = "", descr = "", max = 64)
+ int amount;
+ @NumericProperty(name = "", descr = "", max = 5)
+ float size;
+
+ public DustParticleEffect(Color color, int amount, float size) {
+ this.color = color;
+ this.amount = amount;
+ this.size = size;
+ }
+
+ @Override
+ public void apply(LivingEntity entity) {
+ BloodMobUtil.spawnParticlesAround(entity.getLocation(), Particle.REDSTONE,
+ new Particle.DustOptions(color, size), amount);
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ DustParticleEffect that = (DustParticleEffect) o;
+
+ if (amount != that.amount) return false;
+ if (Float.compare(that.size, size) != 0) return false;
+ return color != null ? color.equals(that.color) : that.color == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = color != null ? color.hashCode() : 0;
+ result = 31 * result + amount;
+ result = 31 * result + (size != +0.0f ? Float.floatToIntBits(size) : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/ParticleEffect.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/ParticleEffect.java
new file mode 100644
index 00000000..55fcd8d1
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/ParticleEffect.java
@@ -0,0 +1,54 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.effect;
+
+import de.eldoria.bloodnight.bloodmob.node.effect.EffectNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.Particle;
+import org.bukkit.entity.LivingEntity;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class ParticleEffect implements EffectNode {
+ @Property(name = "", descr = "")
+ Particle particle;
+ @NumberProperty(name = "", descr = "")
+ int amount;
+
+ public ParticleEffect(Particle particle, int amount) {
+ this.particle = particle;
+ this.amount = amount;
+ }
+
+ @Override
+ public void apply(LivingEntity entity) {
+ BloodMobUtil.spawnParticlesAround(entity.getLocation(), particle, amount);
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ParticleEffect that = (ParticleEffect) o;
+
+ if (amount != that.amount) return false;
+ return particle == that.particle;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = particle != null ? particle.hashCode() : 0;
+ result = 31 * result + amount;
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/PotionEffect.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/PotionEffect.java
new file mode 100644
index 00000000..586bc415
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/effect/PotionEffect.java
@@ -0,0 +1,54 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.effect;
+
+import de.eldoria.bloodnight.bloodmob.node.effect.EffectNode;
+import de.eldoria.bloodnight.bloodmob.utils.BloodMobUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class PotionEffect implements EffectNode {
+ PotionEffectType type;
+ int amplifier;
+ boolean visible;
+
+ public PotionEffect(PotionEffectType type, int amplifier, boolean visible) {
+ this.type = type;
+ this.amplifier = amplifier;
+ this.visible = visible;
+ }
+
+ @Override
+ public void apply(LivingEntity entity) {
+ BloodMobUtil.addPotionEffect(entity, type, amplifier, visible);
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PotionEffect that = (PotionEffect) o;
+
+ if (amplifier != that.amplifier) return false;
+ if (visible != that.visible) return false;
+ return type != null ? type.equals(that.type) : that.type == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + amplifier;
+ result = 31 * result + (visible ? 1 : 0);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/CooldownFilter.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/CooldownFilter.java
new file mode 100644
index 00000000..9295f020
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/CooldownFilter.java
@@ -0,0 +1,78 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.filter;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.filter.FilterNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import de.eldoria.eldoutilities.utils.EnumUtil;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.jetbrains.annotations.NotNull;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Map;
+
+@NoArgsConstructor
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public class CooldownFilter extends FilterNode {
+ @Property(name = "", descr = "")
+ private Duration duration;
+ @JsonIgnore
+ private Instant last = Instant.now();
+
+ public CooldownFilter(int duration, Node nextNode) {
+ super(nextNode);
+ this.duration = Duration.of(duration, ChronoUnit.SECONDS);
+ }
+
+ public CooldownFilter(Map objectMap) {
+ super(objectMap);
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ duration = Duration.of(
+ map.getValue("duration"),
+ EnumUtil.parse(map.getValueOrDefault("unit", ChronoUnit.SECONDS.name()), ChronoUnit.class));
+ }
+
+ @Override
+ @NotNull
+ public Map serialize() {
+ return SerializationUtil.newBuilder(super.serialize())
+ .add("duration", duration.getSeconds())
+ .add("unit", ChronoUnit.SECONDS.name())
+ .build();
+ }
+
+ @Override
+ public boolean check(IBloodMob mob, ContextContainer context) {
+ if (last.plus(duration).isAfter(Instant.now())) {
+ last = Instant.now();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CooldownFilter that = (CooldownFilter) o;
+
+ if (duration != null ? !duration.equals(that.duration) : that.duration != null) return false;
+ return last != null ? last.equals(that.last) : that.last == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = duration != null ? duration.hashCode() : 0;
+ result = 31 * result + (last != null ? last.hashCode() : 0);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/LastDamage.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/LastDamage.java
new file mode 100644
index 00000000..6b91dd9c
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/LastDamage.java
@@ -0,0 +1,59 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.filter;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.filter.FilterNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import lombok.NoArgsConstructor;
+import org.jetbrains.annotations.NotNull;
+
+import java.time.Instant;
+import java.util.Map;
+
+@NoArgsConstructor
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "clazz")
+public class LastDamage extends FilterNode {
+ @NumberProperty(name = "", descr = "")
+ private int after;
+
+ public LastDamage(Node node, int after) {
+ super(node);
+ this.after = after;
+ }
+
+ public LastDamage(Node node) {
+ super(node);
+ }
+
+ public LastDamage(Map objectMap) {
+ super(objectMap);
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean check(IBloodMob mob, ContextContainer context) {
+ return mob.lastDamage().isBefore(Instant.now().minusSeconds(after));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LastDamage that = (LastDamage) o;
+
+ return after == that.after;
+ }
+
+ @Override
+ public int hashCode() {
+ return after;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/PredicateFilter.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/PredicateFilter.java
new file mode 100644
index 00000000..bfe0f6c6
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/filter/PredicateFilter.java
@@ -0,0 +1,64 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.filter;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.filter.FilterNode;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+@NoArgsConstructor
+public class PredicateFilter extends FilterNode {
+ @Property(name = "", descr = "")
+ boolean invert = false;
+ @Property(name = "", descr = "")
+ private PredicateNode predicate;
+
+ public PredicateFilter(Node node, boolean invert, PredicateNode predicate) {
+ super(node);
+ this.invert = invert;
+ this.predicate = predicate;
+ }
+
+ public PredicateFilter(Node node) {
+ super(node);
+ }
+
+ public PredicateFilter(Map objectMap) {
+ super(objectMap);
+ }
+
+ @Override
+ public boolean check(IBloodMob mob, ContextContainer context) {
+ return invert != predicate.test(mob, context);
+ }
+
+ @Override
+ public Set> getClasses(Set> set) {
+ set.add(predicate.getClass());
+ return super.getClasses(set);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PredicateFilter that = (PredicateFilter) o;
+
+ if (invert != that.invert) return false;
+ return Objects.equals(predicate, that.predicate);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (invert ? 1 : 0);
+ result = 31 * result + (predicate != null ? predicate.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/mapper/MoveToLocation.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/mapper/MoveToLocation.java
new file mode 100644
index 00000000..bd007faf
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/mapper/MoveToLocation.java
@@ -0,0 +1,70 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.mapper;
+
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.node.mapper.MapperNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import de.eldoria.eldoutilities.utils.EnumUtil;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+@NoArgsConstructor
+public class MoveToLocation extends MapperNode {
+ @Property(name = "", descr = "")
+ private LocationSource source = LocationSource.OLD;
+
+ public MoveToLocation(Node node, LocationSource source) {
+ super(node);
+ this.source = source;
+ }
+
+ public MoveToLocation(Map objectMap) {
+ super(objectMap);
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ source = map.getValueOrDefault("source", source, s -> EnumUtil.parse(s, LocationSource.class, source));
+ }
+
+ @Override
+ public void map(ContextContainer context) {
+ context.transform(ContextType.MOVE, ContextType.LOCATION, move -> {
+ switch (source) {
+ case OLD:
+ return move;
+ case NEW:
+ return move::getNewLocation;
+ default:
+ throw new IllegalStateException("Unexpected value: " + source);
+ }
+ //TODO
+ }, "");
+ }
+
+ @Override
+ public ContextContainer getTransformedOutput(ContextContainer context) {
+ map(context);
+ return nextNode() != null ? nextNode().getTransformedOutput(context) : context;
+ }
+
+ public enum LocationSource {
+ OLD, NEW
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MoveToLocation that = (MoveToLocation) o;
+
+ return source == that.source;
+ }
+
+ @Override
+ public int hashCode() {
+ return source != null ? source.hashCode() : 0;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/HasTarget.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/HasTarget.java
new file mode 100644
index 00000000..5032fddd
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/HasTarget.java
@@ -0,0 +1,37 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.predicate;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import lombok.NoArgsConstructor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@JsonSerialize
+@NoArgsConstructor
+public class HasTarget implements PredicateNode {
+
+ @Override
+ public boolean test(IBloodMob mob, ContextContainer context) {
+ return mob.getBase().getTarget() != null;
+ }
+
+ @NotNull
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ return obj.getClass() == getClass();
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsDamageCause.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsDamageCause.java
new file mode 100644
index 00000000..c102e375
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsDamageCause.java
@@ -0,0 +1,63 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.predicate;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IDamageCauseContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import de.eldoria.eldoutilities.utils.EnumUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+@RequiresContext(IDamageCauseContext.class)
+public class IsDamageCause implements PredicateNode {
+ @Property(name = "", descr = "")
+ private EntityDamageEvent.DamageCause cause;
+
+ public IsDamageCause(EntityDamageEvent.DamageCause cause) {
+ this.cause = cause;
+ }
+
+ public IsDamageCause(Map objectMap) {
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ cause = map.getValue("cause", s -> EnumUtil.parse(s, EntityDamageEvent.DamageCause.class));
+ }
+
+ @Override
+ @NotNull
+ public Map serialize() {
+ return SerializationUtil.newBuilder()
+ .add("cause", cause.name())
+ .build();
+ }
+
+ @Override
+ public boolean test(IBloodMob mob, ContextContainer context) {
+ return context.get(ContextType.DAMAGE_CAUSE)
+ .map(cause -> this.cause == cause.getDamageCause())
+ .orElse(false);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IsDamageCause that = (IsDamageCause) o;
+
+ return cause == that.cause;
+ }
+
+ @Override
+ public int hashCode() {
+ return cause != null ? cause.hashCode() : 0;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsEntityType.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsEntityType.java
new file mode 100644
index 00000000..75186909
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/nodeimpl/predicate/IsEntityType.java
@@ -0,0 +1,61 @@
+package de.eldoria.bloodnight.bloodmob.nodeimpl.predicate;
+
+import de.eldoria.bloodnight.bloodmob.IBloodMob;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IEntityContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextType;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.eldoutilities.serialization.SerializationUtil;
+import de.eldoria.eldoutilities.serialization.TypeResolvingMap;
+import de.eldoria.eldoutilities.utils.EnumUtil;
+import lombok.NoArgsConstructor;
+import org.bukkit.entity.EntityType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+@NoArgsConstructor
+@RequiresContext(IEntityContext.class)
+public class IsEntityType implements PredicateNode {
+ @Property(name = "", descr = "")
+ private EntityType type;
+
+ public IsEntityType(EntityType type) {
+ this.type = type;
+ }
+
+ public IsEntityType(Map objectMap) {
+ TypeResolvingMap map = SerializationUtil.mapOf(objectMap);
+ type = map.getValue("types", s -> EnumUtil.parse(s, EntityType.class));
+ }
+
+ @Override
+ @NotNull
+ public Map serialize() {
+ return SerializationUtil.newBuilder()
+ .add("types", type.name())
+ .build();
+ }
+
+ @Override
+ public boolean test(IBloodMob mob, ContextContainer context) {
+ return context.get(ContextType.ENTITY).map(c -> type == c.getEntity().getType()).orElse(false);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IsEntityType that = (IsEntityType) o;
+
+ return type == that.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return type != null ? type.hashCode() : 0;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/MobRegistry.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/MobRegistry.java
new file mode 100644
index 00000000..c1828be1
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/MobRegistry.java
@@ -0,0 +1,20 @@
+package de.eldoria.bloodnight.bloodmob.registry;
+
+import de.eldoria.bloodnight.bloodmob.settings.MobConfiguration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MobRegistry {
+ private final Map configurations = new HashMap<>();
+
+ public List getConfigurations() {
+ return new ArrayList<>(configurations.values());
+ }
+
+ public void register(MobConfiguration mobConfiguration) {
+ configurations.put(mobConfiguration.identifier(), mobConfiguration);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/NodeRegistry.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/NodeRegistry.java
new file mode 100644
index 00000000..b5bda4e4
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/NodeRegistry.java
@@ -0,0 +1,141 @@
+package de.eldoria.bloodnight.bloodmob.registry;
+
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.NodeHolder;
+import de.eldoria.bloodnight.bloodmob.node.annotations.RequiresContext;
+import de.eldoria.bloodnight.bloodmob.node.context.IContext;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainer;
+import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainerFactory;
+import de.eldoria.bloodnight.bloodmob.node.effect.EffectNode;
+import de.eldoria.bloodnight.bloodmob.node.filter.FilterNode;
+import de.eldoria.bloodnight.bloodmob.node.mapper.MapperNode;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.ApplyDamage;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.CancelEvent;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.LaunchProjectileOnTarget;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.PotionCloudAction;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.RemoveSelfPotion;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.SearchNearPlayerTarget;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.SelfPotion;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.SetEquipment;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.action.TeleportToTarget;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.effect.DustParticleEffect;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.effect.ParticleEffect;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.filter.LastDamage;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.filter.PredicateFilter;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.mapper.MoveToLocation;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.HasTarget;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.IsDamageCause;
+import de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.IsEntityType;
+import de.eldoria.bloodnight.bloodmob.settings.BehaviourNodeType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class NodeRegistry {
+ private static final Map, List>> NODES = new HashMap<>();
+
+ static {
+ registerNode(ApplyDamage.class);
+ registerNode(CancelEvent.class);
+ registerNode(LaunchProjectileOnTarget.class);
+ registerNode(OtherPotion.class);
+ registerNode(PotionCloudAction.class);
+ registerNode(RemoveSelfPotion.class);
+ registerNode(SearchNearPlayerTarget.class);
+ registerNode(SelfPotion.class);
+ registerNode(SetEquipment.class);
+ registerNode(TeleportToTarget.class);
+ registerNode(DustParticleEffect.class);
+ registerNode(ParticleEffect.class);
+ registerNode(ParticleEffect.class);
+ registerNode(CooldownFilter.class);
+ registerNode(LastDamage.class);
+ registerNode(PredicateFilter.class);
+ registerNode(MoveToLocation.class);
+ registerNode(HasTarget.class);
+ registerNode(IsDamageCause.class);
+ registerNode(IsEntityType.class);
+ }
+
+ public static void registerNode(Class> clazz) {
+ if (isEndNode(clazz)) addIfInstance(Node.class, clazz);
+ addIfInstance(NodeHolder.class, clazz);
+ addIfInstance(EffectNode.class, clazz);
+ addIfInstance(FilterNode.class, clazz);
+ addIfInstance(MapperNode.class, clazz);
+ addIfInstance(PredicateNode.class, clazz);
+ }
+
+ public static boolean isEndNode(Class> clazz) {
+ return !NodeHolder.class.isAssignableFrom(clazz);
+ }
+
+ public static Set> nodeSet() {
+ return NODES.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
+ }
+
+ public static Set> getAvailableNodes(Node node, ContextContainer container) {
+ Node lastNode = node.getLast();
+ if (isEndNode(lastNode.getClass())) {
+ return Collections.emptySet();
+ }
+
+ return getMatchingClasses(node.getTransformedOutput(container));
+ }
+
+ public static Set> getAvailableNodes(BehaviourNodeType type) {
+ ContextContainer context = ContextContainerFactory.mock(type);
+
+ return getMatchingClasses(context);
+ }
+
+ public static List> nodes() {
+ ArrayList> classes = new ArrayList<>(NODES.get(Node.class));
+ classes.addAll(NODES.get(NodeHolder.class));
+ return classes;
+ }
+
+ public static List> predicates() {
+ return NODES.get(PredicateNode.class);
+ }
+
+ @NotNull
+ private static Set> getMatchingClasses(ContextContainer context) {
+ ArrayList> classes = new ArrayList<>(NODES.get(Node.class));
+ classes.addAll(NODES.get(NodeHolder.class));
+
+
+ return classes.stream().filter(clazz -> {
+ if (!clazz.isAnnotationPresent(RequiresContext.class)) {
+ return true;
+ }
+ RequiresContext annotation = clazz.getAnnotation(RequiresContext.class);
+ for (Class extends IContext> aClazz : annotation.value()) {
+ if (!context.contains(aClazz)) {
+ return false;
+ }
+ }
+ return true;
+ }).collect(Collectors.toSet());
+ }
+
+ private static void addIfInstance(Class> ref, Class> clazz) {
+ if (ref.isAssignableFrom(clazz)) {
+ getClassList(ref).add(clazz);
+ }
+ }
+
+ private static List> getClassList(Class> clazz) {
+ return NODES.computeIfAbsent(clazz, k -> new ArrayList<>());
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/ItemRegistry.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/ItemRegistry.java
new file mode 100644
index 00000000..59dab341
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/ItemRegistry.java
@@ -0,0 +1,30 @@
+package de.eldoria.bloodnight.bloodmob.registry.items;
+
+import org.bukkit.inventory.ItemStack;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ItemRegistry {
+ private int currentId = 0;
+ private Map items = new HashMap<>();
+
+ public ItemRegistry() {
+ }
+
+ public List getAsSimpleItems() {
+ return items.entrySet().stream()
+ .map(entry -> SimpleItem.from(entry.getKey(), entry.getValue()))
+ .collect(Collectors.toList());
+ }
+
+ public void register(ItemStack stack) {
+ items.put(currentId++, stack);
+ }
+
+ public ItemStack getItem(int id) {
+ return items.get(id);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/SimpleItem.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/SimpleItem.java
new file mode 100644
index 00000000..7d70211d
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/registry/items/SimpleItem.java
@@ -0,0 +1,109 @@
+package de.eldoria.bloodnight.bloodmob.registry.items;
+
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.MapProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.StringProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.value.ValueType;
+import de.eldoria.eldoutilities.container.Pair;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Simplified item without usage of the bukkit api.
+ */
+public class SimpleItem {
+ @NumberProperty(name = "", descr = "", max = Integer.MAX_VALUE)
+ private int id;
+ @StringProperty(name = "", descr = "")
+ private String type;
+ @MapProperty(name = "", descr = "", key = ValueType.STRING, value = ValueType.NUMBER)
+ private Map enchantment;
+ @Property(name = "", descr = "")
+ private List lore;
+ @StringProperty(name = "", descr = "")
+ private String displayName;
+
+ public SimpleItem() {
+ }
+
+ public SimpleItem(int id, @NotNull Material type, @NotNull Map enchantments,
+ @NotNull List lore, String displayName) {
+ this.id = id;
+ this.type = type.name();
+ this.enchantment = enchantments;
+ this.lore = lore;
+ this.displayName = displayName;
+ }
+
+ public static SimpleItem from(int id, ItemStack stack) {
+ Material type = stack.getType();
+ ItemMeta itemMeta = stack.getItemMeta();
+
+ Map enchantments = stack.getEnchantments()
+ .entrySet()
+ .stream()
+ .map(entry -> Pair.of(entry.getKey().getKey().getKey(), entry.getValue()))
+ .collect(Collectors.toMap(entry -> entry.first, entry -> entry.second));
+ List lore = new ArrayList<>();
+ String displayName = null;
+ if (itemMeta != null) {
+ if (itemMeta.hasLore()) lore = itemMeta.getLore();
+ if (itemMeta.hasDisplayName()) displayName = itemMeta.getDisplayName();
+ }
+ return new SimpleItem(id, type, enchantments, lore, displayName);
+ }
+
+ public int id() {
+ return id;
+ }
+
+ public Material type() {
+ return Material.valueOf(type);
+ }
+
+ public Map enchantments() {
+ return enchantment;
+ }
+
+ public List lore() {
+ return lore;
+ }
+
+ public String displayName() {
+ return displayName;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SimpleItem that = (SimpleItem) o;
+
+ if (id != that.id) return false;
+ if (type != that.type) return false;
+ if (!Objects.equals(enchantment, that.enchantment)) return false;
+ if (!Objects.equals(lore, that.lore)) return false;
+ return Objects.equals(displayName, that.displayName);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id;
+ result = 31 * result + (type != null ? type.hashCode() : 0);
+ result = 31 * result + (enchantment != null ? enchantment.hashCode() : 0);
+ result = 31 * result + (lore != null ? lore.hashCode() : 0);
+ result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PotionEffectTypeAdapter.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PotionEffectTypeAdapter.java
new file mode 100644
index 00000000..41437577
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PotionEffectTypeAdapter.java
@@ -0,0 +1,35 @@
+package de.eldoria.bloodnight.bloodmob.serialization;
+
+import org.bukkit.potion.PotionEffectType;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PotionEffectTypeAdapter {
+ private static final Map byId = new HashMap<>();
+ private static final Map byName = new HashMap<>();
+
+ static {
+ for (Field field : PotionEffectType.class.getDeclaredFields()) {
+ if (field.getType().equals(PotionEffectType.class)) {
+ PotionEffectType potionEffectType;
+ try {
+ potionEffectType = (PotionEffectType) field.get(null);
+ } catch (IllegalAccessException e) {
+ continue;
+ }
+ byId.put(potionEffectType.getId(), field.getName());
+ byName.put(field.getName(), potionEffectType);
+ }
+ }
+ }
+
+ public static String idToName(int id) {
+ return byId.get(id);
+ }
+
+ public static PotionEffectType nameToEffect(String id) {
+ return byName.get(id);
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PropertyGenerator.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PropertyGenerator.java
new file mode 100644
index 00000000..a1276073
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/PropertyGenerator.java
@@ -0,0 +1,276 @@
+package de.eldoria.bloodnight.bloodmob.serialization;
+
+import de.eldoria.bloodnight.bloodmob.node.Node;
+import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.EnumLikeProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.ItemProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.MapProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.MultiListProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumericProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property;
+import de.eldoria.bloodnight.bloodmob.serialization.annotation.StringProperty;
+import de.eldoria.bloodnight.bloodmob.serialization.value.MapValueEntry;
+import de.eldoria.bloodnight.bloodmob.serialization.value.SimpleValue;
+import de.eldoria.bloodnight.bloodmob.serialization.value.Value;
+import de.eldoria.bloodnight.bloodmob.serialization.value.ValueProperties;
+import de.eldoria.bloodnight.bloodmob.serialization.value.ValueType;
+import de.eldoria.bloodnight.bloodmob.settings.Behaviour;
+import de.eldoria.bloodnight.bloodmob.settings.Drops;
+import de.eldoria.bloodnight.bloodmob.settings.Equipment;
+import de.eldoria.bloodnight.bloodmob.settings.Extension;
+import de.eldoria.bloodnight.bloodmob.settings.Stats;
+import de.eldoria.eldoutilities.container.Pair;
+import de.eldoria.eldoutilities.utils.ReflectionUtil;
+import org.bukkit.Color;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffectType;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class PropertyGenerator {
+ private static final Map, List> CLASS_VALUES = new HashMap<>();
+
+ static {
+ registerEnumLikeAdapter(PotionEffectType.class, enumLikeToList(PotionEffectType.class));
+ }
+
+ public static List enumLikeToList(Class clazz) {
+ return Arrays.stream(clazz.getDeclaredFields())
+ .filter(field -> field.getType().equals(clazz))
+ .map(Field::getName)
+ .collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ public static void registerEnumLikeAdapter(Class> clazz, List values) {
+ CLASS_VALUES.put(clazz, values);
+ }
+
+ public static List generateValues(Class clazz) {
+ Field[] declaredFields = ReflectionUtil.getAllFields(clazz);
+ List values = new ArrayList<>();
+ for (Field declaredField : declaredFields) {
+ if (declaredField.isAnnotationPresent(Property.class)) {
+ values.add(buildProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent(EnumLikeProperty.class)) {
+ values.add(buildEnumLikeProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent(NumberProperty.class)) {
+ values.add(buildNumberProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent(NumericProperty.class)) {
+ values.add(buildNumericProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent(StringProperty.class)) {
+ values.add(buildStringProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent((MultiListProperty.class))) {
+ values.add(buildMultiListProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent((MapProperty.class))) {
+ values.add(buildMapProperty(declaredField));
+ }
+ if (declaredField.isAnnotationPresent((ItemProperty.class))) {
+ values.add(buildItemProperty(declaredField));
+ }
+ }
+ return values;
+ }
+
+ public static Pair getClassProperty(Class clazz) {
+ if (clazz.isAnnotationPresent(Property.class)) {
+ Property annotation = clazz.getAnnotation(Property.class);
+ return Pair.of(annotation.name(), annotation.descr());
+ }
+ return Pair.of(null, null);
+ }
+
+ private static SimpleValue buildItemProperty(Field field) {
+ ItemProperty annotation = field.getAnnotation(ItemProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+ return new SimpleValue(id, name, descr, ValueType.ITEM);
+ }
+
+ private static SimpleValue buildMultiListProperty(Field field) {
+ MultiListProperty annotation = field.getAnnotation(MultiListProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+ Class> type;
+ if (field.getType().isArray()) {
+ type = field.getType().getComponentType();
+ } else {
+ // Gonna assume that this is some kind of single dimension collection.
+ type = (Class>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+ }
+ // Enums
+ if (type.isEnum()) {
+ List values = Arrays.stream(type.getEnumConstants())
+ .map(e -> ((Enum>) e).name())
+ .collect(Collectors.toList());
+ return new Value<>(id, name, descr, ValueType.MULTI_LIST, values);
+ }
+ // Color
+ if (field.getType().equals(Color.class)) {
+ return new Value<>(id, name, descr, ValueType.MULTI_LIST, ValueType.COLOR);
+ }
+ // Drops
+ if (field.getType().equals(Drops.class)) {
+ return new Value<>(id, name, descr, ValueType.MULTI_LIST, ValueType.DROPS);
+ }
+ return null;
+ }
+
+ private static SimpleValue buildMapProperty(Field field) {
+ MapProperty annotation = field.getAnnotation(MapProperty.class);
+ Class> key = (Class>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+ Class> value = (Class>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[1];
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+
+ MapValueEntry keyValue;
+ if (key.isEnum()) {
+ List enumValues = getEnumValues(key);
+ keyValue = MapValueEntry.withValues(enumValues);
+ } else {
+ keyValue = new MapValueEntry(annotation.key());
+ }
+
+ MapValueEntry valueValue;
+ if (value.isEnum()) {
+ List enumValues = getEnumValues(key);
+ valueValue = MapValueEntry.withValues(enumValues);
+ } else {
+ valueValue = new MapValueEntry(annotation.value());
+ }
+
+ return new Value<>(id, name, descr, ValueType.MAP, ValueProperties.ofMaps(keyValue, valueValue));
+ }
+
+ private static SimpleValue buildStringProperty(Field field) {
+ StringProperty annotation = field.getAnnotation(StringProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+
+ String pattern = annotation.pattern();
+ int min = annotation.min();
+ int max = annotation.max();
+ return new Value<>(id, name, descr, ValueType.STRING, ValueProperties.ofString(pattern, min, max));
+ }
+
+ private static SimpleValue buildEnumLikeProperty(Field field) {
+ EnumLikeProperty annotation = field.getAnnotation(EnumLikeProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+
+ if (CLASS_VALUES.containsKey(field.getType())) {
+ return new Value<>(id, name, descr, ValueType.LIST, CLASS_VALUES.get(field.getType()));
+ }
+ throw new IllegalArgumentException("No enum like adapter is registered for field " + field.getDeclaringClass().getName() + "#" + field.getName() + " of type " + field.getType().getSimpleName());
+
+ }
+
+ private static SimpleValue buildProperty(Field field) {
+ Property annotation = field.getAnnotation(Property.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+ // Enums
+ if (field.getType().isEnum()) {
+ List values = Arrays.stream(field.getType().getEnumConstants())
+ .map(e -> ((Enum>) e).name())
+ .collect(Collectors.toList());
+ return new Value<>(id, name, descr, ValueType.LIST, values);
+ }
+ // Boolean
+ if (field.getType().equals(boolean.class)) {
+ return new SimpleValue(id, name, descr, ValueType.BOOLEAN);
+ }
+ // Color
+ if (field.getType().equals(Color.class)) {
+ return new SimpleValue(id, name, descr, ValueType.COLOR);
+ }
+ // Predicate
+ if (field.getType().equals(PredicateNode.class)) {
+ return new SimpleValue(id, name, descr, ValueType.PREDICATE);
+ }
+ // Item Stacks
+ if (field.getType().equals(ItemStack.class)) {
+ return new SimpleValue(id, name, descr, ValueType.ITEM);
+ }
+ // Equipment
+ if (field.getType().equals(Equipment.class)) {
+ return new SimpleValue(id, name, descr, ValueType.EQUIPMENT);
+ }
+ // Duration
+ if (field.getType().equals(Duration.class)) {
+ return new SimpleValue(id, name, descr, ValueType.NUMBER);
+ }
+ // Extension
+ if (field.getType().equals(Extension.class)) {
+ return new SimpleValue(id, name, descr, ValueType.EXTENSION);
+ }
+ // Stats
+ if (field.getType().equals(Stats.class)) {
+ return new SimpleValue(id, name, descr, ValueType.STATS);
+ }
+ // Drops
+ if (field.getType().equals(Drops.class)) {
+ return new SimpleValue(id, name, descr, ValueType.DROPS);
+ }
+ // Behaviour
+ if (field.getType().equals(Behaviour.class)) {
+ return new SimpleValue(id, name, descr, ValueType.BEHAVIOUR);
+ }
+ if (field.getType().equals(List.class)) {
+ Class> type = (Class>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+ return new Value<>(id, name, descr, ValueType.LIST, generateValues(type));
+ }
+ if (field.getType().equals(Node.class)) {
+ return new SimpleValue(id, name, descr, ValueType.NODE);
+ }
+ throw new IllegalArgumentException("Field " + field.getDeclaringClass().getName() + "#" + field.getName() + " is can not be converted.");
+ }
+
+ private static SimpleValue buildNumberProperty(Field field) {
+ NumberProperty annotation = field.getAnnotation(NumberProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+ int min = annotation.min();
+ int max = annotation.max();
+
+ return new Value<>(id, name, descr, ValueType.NUMBER, ValueProperties.ofInts(min, max));
+ }
+
+ private static SimpleValue buildNumericProperty(Field field) {
+ NumericProperty annotation = field.getAnnotation(NumericProperty.class);
+ String id = field.getName();
+ String name = annotation.name();
+ String descr = annotation.descr();
+ float min = annotation.min();
+ float max = annotation.max();
+
+ return new Value<>(id, name, descr, ValueType.NUMERIC, ValueProperties.ofFloats(min, max));
+ }
+
+ private static List getEnumValues(Class> clazz) {
+ return Arrays.stream(clazz.getEnumConstants())
+ .map(e -> ((Enum>) e).name())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/Values.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/Values.java
new file mode 100644
index 00000000..bd9c0822
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/Values.java
@@ -0,0 +1,4 @@
+package de.eldoria.bloodnight.bloodmob.serialization;
+
+public interface Values {
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/EnumLikeProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/EnumLikeProperty.java
new file mode 100644
index 00000000..cc13fc55
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/EnumLikeProperty.java
@@ -0,0 +1,14 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface EnumLikeProperty {
+ String name();
+
+ String descr();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/ItemProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/ItemProperty.java
new file mode 100644
index 00000000..bf7d136b
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/ItemProperty.java
@@ -0,0 +1,13 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ItemProperty {
+ String name();
+ String descr();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MapProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MapProperty.java
new file mode 100644
index 00000000..44a7841f
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MapProperty.java
@@ -0,0 +1,24 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+
+import de.eldoria.bloodnight.bloodmob.serialization.value.SimpleValue;
+import de.eldoria.bloodnight.bloodmob.serialization.value.Value;
+import de.eldoria.bloodnight.bloodmob.serialization.value.ValueType;
+
+import javax.management.ValueExp;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface MapProperty {
+ String name();
+
+ String descr();
+
+ ValueType key();
+
+ ValueType value();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MultiListProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MultiListProperty.java
new file mode 100644
index 00000000..3c66f420
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/MultiListProperty.java
@@ -0,0 +1,13 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface MultiListProperty {
+ String name();
+ String descr();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumberProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumberProperty.java
new file mode 100644
index 00000000..dfda52a2
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumberProperty.java
@@ -0,0 +1,19 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface NumberProperty {
+ String name();
+
+ String descr();
+
+ int min() default 0;
+
+ int max() default 1024;
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumericProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumericProperty.java
new file mode 100644
index 00000000..07f1b933
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/NumericProperty.java
@@ -0,0 +1,19 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface NumericProperty {
+ String name();
+
+ String descr();
+
+ float min() default 0;
+
+ float max() default 1024;
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/Property.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/Property.java
new file mode 100644
index 00000000..da335527
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/Property.java
@@ -0,0 +1,13 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.TYPE})
+public @interface Property {
+ String name();
+ String descr();
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/StringProperty.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/StringProperty.java
new file mode 100644
index 00000000..9403adf4
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/annotation/StringProperty.java
@@ -0,0 +1,16 @@
+package de.eldoria.bloodnight.bloodmob.serialization.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface StringProperty {
+ String name();
+ String descr();
+ String pattern() default "";
+ int min() default 0;
+ int max() default 32;
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/MobEditorPayload.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/MobEditorPayload.java
new file mode 100644
index 00000000..70a500fc
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/MobEditorPayload.java
@@ -0,0 +1,16 @@
+package de.eldoria.bloodnight.bloodmob.serialization.container;
+
+public class MobEditorPayload {
+ private SettingsContainer settingsContainer = null;
+
+ public MobEditorPayload() {
+ }
+
+ public MobEditorPayload(SettingsContainer settingsContainer) {
+ this.settingsContainer = settingsContainer;
+ }
+
+ public SettingsContainer settingsContainer() {
+ return settingsContainer;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/SettingsContainer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/SettingsContainer.java
new file mode 100644
index 00000000..71cf95ef
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/container/SettingsContainer.java
@@ -0,0 +1,85 @@
+package de.eldoria.bloodnight.bloodmob.serialization.container;
+
+import de.eldoria.bloodnight.bloodmob.drop.Drop;
+import de.eldoria.bloodnight.bloodmob.registry.MobRegistry;
+import de.eldoria.bloodnight.bloodmob.registry.items.ItemRegistry;
+import de.eldoria.bloodnight.bloodmob.registry.items.SimpleItem;
+import de.eldoria.bloodnight.bloodmob.settings.MobConfiguration;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class SettingsContainer {
+ List configurations;
+ List items;
+ List globalDrops;
+
+ public SettingsContainer() {
+ }
+
+ private SettingsContainer(List configurations, List items, List globalDrops) {
+ this.configurations = configurations;
+ this.items = items;
+ this.globalDrops = globalDrops;
+ }
+
+ public static SettingsContainer from(ItemRegistry itemRegistry, MobRegistry mobRegistry, List globalDrops) {
+ List asSimpleItems = itemRegistry.getAsSimpleItems();
+ List configurations = mobRegistry.getConfigurations();
+ return new SettingsContainer(configurations, asSimpleItems, globalDrops);
+ }
+
+ public List configurations() {
+ return configurations;
+ }
+
+ public List items() {
+ return items;
+ }
+
+ public List globalDrops() {
+ return globalDrops;
+ }
+
+ public List mobIdentifier() {
+ return configurations.stream().map(MobConfiguration::identifier).collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SettingsContainer that = (SettingsContainer) o;
+
+ if (!Objects.equals(configurations, that.configurations)) return false;
+ if (!Objects.equals(items, that.items)) return false;
+ return Objects.equals(globalDrops, that.globalDrops);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = configurations != null ? configurations.hashCode() : 0;
+ result = 31 * result + (items != null ? items.hashCode() : 0);
+ result = 31 * result + (globalDrops != null ? globalDrops.hashCode() : 0);
+ return result;
+ }
+
+ public Optional getMobConfig(String identifier) {
+ return configurations.stream().filter(c -> c.identifier().equals(identifier)).findFirst();
+ }
+
+ public boolean mobExists(String identifier) {
+ return getMobConfig(identifier).isPresent();
+ }
+
+ public void createMob(String identifier) {
+ configurations.add(new MobConfiguration(identifier));
+ }
+
+ public boolean removeMob(String identifier) {
+ return configurations.removeIf(c -> c.identifier().equals(identifier));
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/MobMapper.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/MobMapper.java
new file mode 100644
index 00000000..221b2ba4
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/MobMapper.java
@@ -0,0 +1,36 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter.*;
+import org.bukkit.Color;
+import org.bukkit.potion.PotionEffectType;
+
+import java.time.Duration;
+
+public class MobMapper {
+ private static final ObjectMapper objectMapper;
+
+ static {
+ objectMapper = new ObjectMapper()
+ .setDefaultPrettyPrinter(new DefaultPrettyPrinter())
+ .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
+ .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
+ .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
+ SimpleModule module = new SimpleModule();
+ module.addSerializer(PotionEffectType.class, new PortionEffectTypeSerializer());
+ module.addDeserializer(PotionEffectType.class, new PortionEffectTypeDeserializer());
+ module.addSerializer(Duration.class, new DurationSerializer());
+ module.addDeserializer(Duration.class, new DurationDeserializer());
+ module.addSerializer(Color.class, new BukkitColorSerializer());
+ module.addDeserializer(Color.class, new BukkitColorDeserializer());
+ objectMapper.registerModule(module);
+ }
+
+ public static ObjectMapper mapper() {
+ return objectMapper;
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorDeserializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorDeserializer.java
new file mode 100644
index 00000000..f79d7196
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorDeserializer.java
@@ -0,0 +1,33 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.bukkit.Color;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BukkitColorDeserializer extends StdDeserializer {
+ protected BukkitColorDeserializer(Class t) {
+ super(t);
+ }
+ private static final Pattern HEX = Pattern.compile("#(?[0-9]{2})(?[0-9]{2})(?[0-9]{2})");
+
+ public BukkitColorDeserializer() {
+ this(null);
+ }
+
+ @Override
+ public Color deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ Matcher matcher = HEX.matcher(p.getValueAsString());
+ if(!matcher.find()) return Color.WHITE;
+ return Color.fromRGB(
+ Integer.parseInt(matcher.group("r"), 16),
+ Integer.parseInt(matcher.group("g"), 16),
+ Integer.parseInt(matcher.group("b"), 16));
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorSerializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorSerializer.java
new file mode 100644
index 00000000..cc631f52
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/BukkitColorSerializer.java
@@ -0,0 +1,24 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import org.bukkit.Color;
+
+import java.io.IOException;
+import java.time.Duration;
+
+public class BukkitColorSerializer extends StdSerializer {
+ protected BukkitColorSerializer(Class t) {
+ super(t);
+ }
+
+ public BukkitColorSerializer() {
+ this(null);
+ }
+
+ @Override
+ public void serialize(Color value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(String.format("#%02x%02x%02x", value.getRed(), value.getGreen(), value.getBlue()));
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationDeserializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationDeserializer.java
new file mode 100644
index 00000000..f2e2928c
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationDeserializer.java
@@ -0,0 +1,24 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+import java.io.IOException;
+import java.time.Duration;
+
+public class DurationDeserializer extends StdDeserializer {
+ protected DurationDeserializer(Class t) {
+ super(t);
+ }
+
+ public DurationDeserializer() {
+ this(null);
+ }
+
+ @Override
+ public Duration deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return Duration.ofSeconds(p.getNumberValue().intValue());
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationSerializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationSerializer.java
new file mode 100644
index 00000000..a4c1f73b
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/DurationSerializer.java
@@ -0,0 +1,23 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.time.Duration;
+
+public class DurationSerializer extends StdSerializer {
+ protected DurationSerializer(Class t) {
+ super(t);
+ }
+
+ public DurationSerializer() {
+ this(null);
+ }
+
+ @Override
+ public void serialize(Duration value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeNumber(value.getSeconds());
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/EnchantementSerializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/EnchantementSerializer.java
new file mode 100644
index 00000000..7405ff0c
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/EnchantementSerializer.java
@@ -0,0 +1,24 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import de.eldoria.bloodnight.bloodmob.serialization.PotionEffectTypeAdapter;
+import org.bukkit.potion.PotionEffectType;
+
+import java.io.IOException;
+
+public class EnchantementSerializer extends StdSerializer {
+ protected EnchantementSerializer(Class t) {
+ super(t);
+ }
+
+ public EnchantementSerializer() {
+ this(null);
+ }
+
+ @Override
+ public void serialize(PotionEffectType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(PotionEffectTypeAdapter.idToName(value.getId()));
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeDeserializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeDeserializer.java
new file mode 100644
index 00000000..a5d75e29
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeDeserializer.java
@@ -0,0 +1,25 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import de.eldoria.bloodnight.bloodmob.serialization.PotionEffectTypeAdapter;
+import org.bukkit.potion.PotionEffectType;
+
+import java.io.IOException;
+
+public class PortionEffectTypeDeserializer extends StdDeserializer {
+ protected PortionEffectTypeDeserializer(Class t) {
+ super(t);
+ }
+
+ public PortionEffectTypeDeserializer() {
+ this(null);
+ }
+
+ @Override
+ public PotionEffectType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return PotionEffectTypeAdapter.nameToEffect(p.getValueAsString());
+ }
+}
diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeSerializer.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeSerializer.java
new file mode 100644
index 00000000..890a63b0
--- /dev/null
+++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/mapper/adapter/PortionEffectTypeSerializer.java
@@ -0,0 +1,24 @@
+package de.eldoria.bloodnight.bloodmob.serialization.mapper.adapter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import de.eldoria.bloodnight.bloodmob.serialization.PotionEffectTypeAdapter;
+import org.bukkit.potion.PotionEffectType;
+
+import java.io.IOException;
+
+public class PortionEffectTypeSerializer extends StdSerializer {
+ protected PortionEffectTypeSerializer(Class