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> 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[] 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 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 projectileClazz; + + ProjectileType(Class projectileClazz) { + this.projectileClazz = projectileClazz; + } + + public Class 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 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 t) { + super(t); + } + + public PortionEffectTypeSerializer() { + 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/value/MapValueEntry.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/MapValueEntry.java new file mode 100644 index 00000000..2c43ed99 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/MapValueEntry.java @@ -0,0 +1,24 @@ +package de.eldoria.bloodnight.bloodmob.serialization.value; + +import java.util.List; + +public class MapValueEntry { + protected final ValueType type; + + public MapValueEntry(ValueType type) { + this.type = type; + } + + public static MapValueEntry withValues(List values) { + return new ListValue(values); + } + + public static class ListValue extends MapValueEntry { + private final List values; + + public ListValue(List values) { + super(ValueType.LIST); + this.values = values; + } + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/SimpleValue.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/SimpleValue.java new file mode 100644 index 00000000..61b8abe0 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/SimpleValue.java @@ -0,0 +1,15 @@ +package de.eldoria.bloodnight.bloodmob.serialization.value; + +public class SimpleValue { + protected final String field; + protected final String name; + protected final String descr; + protected final ValueType type; + + public SimpleValue(String field, String name, String descr, ValueType type) { + this.field = field; + this.name = name; + this.descr = descr; + this.type = type; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/Value.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/Value.java new file mode 100644 index 00000000..75732b38 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/Value.java @@ -0,0 +1,10 @@ +package de.eldoria.bloodnight.bloodmob.serialization.value; + +public class Value extends SimpleValue { + private final T values; + + public Value(String field, String name, String descr, ValueType type, T values) { + super(field, name, descr, type); + this.values = values; + } +} \ No newline at end of file diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueProperties.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueProperties.java new file mode 100644 index 00000000..cf71af2a --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueProperties.java @@ -0,0 +1,62 @@ +package de.eldoria.bloodnight.bloodmob.serialization.value; + +import com.google.common.collect.Maps; + +import java.util.List; + +public final class ValueProperties { + public static Maps ofMaps(MapValueEntry key, MapValueEntry value) { + return new Maps(key, value); + } + + public static class Floats { + float min, max; + + private Floats(float min, float max) { + this.min = min; + this.max = max; + } + } + + public static class Ints { + int min, max; + + private Ints(int min, int max) { + this.min = min; + this.max = max; + } + } + + public static class Strings { + private final String pattern; + private final int min; + private final int max; + + private Strings(String pattern, int min, int max) { + this.pattern = pattern; + this.min = min; + this.max = max; + } + } + public static class Maps { + private final MapValueEntry keys; + private final MapValueEntry value; + + public Maps(MapValueEntry keys, MapValueEntry value) { + this.keys = keys; + this.value = value; + } + } + + public static Floats ofFloats(float min, float max) { + return new Floats(min, max); + } + + public static Ints ofInts(int min, int max) { + return new Ints(min, max); + } + + public static Strings ofString(String pattern, int min, int max) { + return new Strings(pattern, min, max); + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueType.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueType.java new file mode 100644 index 00000000..746ec01f --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/serialization/value/ValueType.java @@ -0,0 +1,50 @@ +package de.eldoria.bloodnight.bloodmob.serialization.value; + +import de.eldoria.bloodnight.bloodmob.drop.Drop; +import de.eldoria.bloodnight.bloodmob.node.Node; +import de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode; +import de.eldoria.bloodnight.bloodmob.registry.items.SimpleItem; +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; + +public enum ValueType { + // simple Types + STRING, + NUMBER, + NUMERIC, + BOOLEAN, + // collections + LIST, + MULTI_LIST, + MAP, + // bukkit + COLOR, + ITEM(SimpleItem.class), + // custom settings + EXTENSION(Extension.class), + EQUIPMENT(Equipment.class), + STATS(Stats.class), + DROPS(Drops.class), + DROP(Drop.class), + BEHAVIOUR(Behaviour.class), + // custom objects + PREDICATE(PredicateNode.class), + NODE(Node.class); + + private final Class clazz; + + ValueType(Class stringsClass) { + clazz = stringsClass; + } + + ValueType() { + clazz = null; + } + + public Class clazz() { + return clazz; + } +} \ No newline at end of file diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Behaviour.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Behaviour.java new file mode 100644 index 00000000..3195a914 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Behaviour.java @@ -0,0 +1,74 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import de.eldoria.bloodnight.bloodmob.node.Node; +import de.eldoria.bloodnight.config.ConfigCheck; +import de.eldoria.bloodnight.config.ConfigException; +import de.eldoria.eldoutilities.serialization.SerializationUtil; +import de.eldoria.eldoutilities.serialization.TypeResolvingMap; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class Behaviour implements ConfigCheck, ConfigurationSerializable { + private Map> behaviourMap = new HashMap<>(); + + public Behaviour() { + Arrays.stream(BehaviourNodeType.values()).forEachOrdered(this::getBehaviour); + } + + public List getNodes(BehaviourNodeType node) { + return getBehaviour(node); + } + + public int addNode(BehaviourNodeType type, Node node) { + List behaviour = getBehaviour(type); + behaviour.add(node); + return behaviour.size() -1; + } + + public Map> behaviourMap() { + return Collections.unmodifiableMap(behaviourMap); + } + + private List getBehaviour(BehaviourNodeType type) { + return behaviourMap.computeIfAbsent(type, k -> new ArrayList<>()); + } + + + @Override + public void check(MobConfiguration data) throws ConfigException { + } + + public Behaviour(Map objectMap) { + TypeResolvingMap map = SerializationUtil.mapOf(objectMap); + for (BehaviourNodeType value : BehaviourNodeType.values()) { + behaviourMap.put(value, map.getValueOrDefault(value.name(), new ArrayList<>())); + } + } + + @Override + @NotNull + public Map serialize() { + SerializationUtil.Builder builder = SerializationUtil.newBuilder(); + for (BehaviourNodeType value : BehaviourNodeType.values()) { + builder.add(value.name(), getBehaviour(value)); + } + return builder.build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Behaviour behaviour = (Behaviour) o; + + return Objects.equals(behaviourMap, behaviour.behaviourMap); + } + + @Override + public int hashCode() { + return behaviourMap != null ? behaviourMap.hashCode() : 0; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/BehaviourNodeType.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/BehaviourNodeType.java new file mode 100644 index 00000000..4f755e4a --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/BehaviourNodeType.java @@ -0,0 +1,17 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +public enum BehaviourNodeType { + TICK, + ON_END, + ON_TELEPORT, + ON_PROJECTILE_SHOOT, + ON_PROJECTILE_HIT, + ON_DEATH, + ON_KILL, + ON_EXPLOSION_PRIME, + ON_EXPLOSION, + ON_TARGET, + ON_DAMAGE, + ON_DAMAGE_BY_ENTITY, + ON_HIT +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Drops.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Drops.java new file mode 100644 index 00000000..2a15dac1 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Drops.java @@ -0,0 +1,70 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import com.fasterxml.jackson.databind.annotation.JsonAppend; +import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty; +import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property; +import de.eldoria.bloodnight.config.ConfigCheck; +import de.eldoria.bloodnight.config.ConfigException; +import de.eldoria.bloodnight.bloodmob.drop.Drop; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public class Drops implements ConfigCheck { + + /** + * Min amount of drops. + */ + @NumberProperty(name = "", descr = "", min = -1, max = 64) + private int minDrops = -1; + + /** + * Max amount of drops. + */ + @NumberProperty(name = "", descr = "", min = -1, max = 64) + private int maxDrops = -1; + + /** + * If this is true only drops from mobs are choosen and default drops will not drop. if false the drops will be + * added to default drops. + */ + @Property(name = "", descr = "") + private boolean overrideDefaultDrops; + + /** + * The drops of this mob. + */ + @Property(name = "", descr = "") + private List drops = new ArrayList<>(); + + @Override + public void check(Object data) throws ConfigException { + ConfigCheck.isInRange(minDrops, -1, 64, "minDrops"); + ConfigCheck.isInRange(maxDrops, minDrops, 64, "maxDrops"); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Drops drops1 = (Drops) o; + + if (minDrops != drops1.minDrops) return false; + if (maxDrops != drops1.maxDrops) return false; + if (overrideDefaultDrops != drops1.overrideDefaultDrops) return false; + return drops != null ? drops.equals(drops1.drops) : drops1.drops == null; + } + + @Override + public int hashCode() { + int result = minDrops; + result = 31 * result + maxDrops; + result = 31 * result + (overrideDefaultDrops ? 1 : 0); + result = 31 * result + (drops != null ? drops.hashCode() : 0); + return result; + } +} \ No newline at end of file diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Equipment.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Equipment.java new file mode 100644 index 00000000..bfdf6936 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Equipment.java @@ -0,0 +1,102 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import de.eldoria.bloodnight.bloodmob.registry.items.ItemRegistry; +import de.eldoria.bloodnight.bloodmob.registry.items.SimpleItem; +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 org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class Equipment implements ConfigurationSerializable { + @ItemProperty(name = "", descr = "") + private int mainHand = -1; + @ItemProperty(name = "", descr = "") + private int offHand = -1; + @ItemProperty(name = "", descr = "") + private int helmet = -1; + @ItemProperty(name = "", descr = "") + private int chestplate = -1; + @ItemProperty(name = "", descr = "") + private int leggings = -1; + @ItemProperty(name = "", descr = "") + private int boots = -1; + + public Equipment() { + } + + public Equipment(Map objectMap) { + TypeResolvingMap map = SerializationUtil.mapOf(objectMap); + mainHand = map.getValueOrDefault("mainHand", mainHand); + offHand = map.getValueOrDefault("offHand", offHand); + helmet = map.getValueOrDefault("helmet", helmet); + chestplate = map.getValueOrDefault("chestplate", chestplate); + leggings = map.getValueOrDefault("leggings", leggings); + boots = map.getValueOrDefault("boots", boots); + } + + /** + * 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 SerializationUtil.newBuilder() + .add("mainHand", mainHand) + .add("offHand", offHand) + .add("helmet", helmet) + .add("chestplate", chestplate) + .add("leggings", leggings) + .add("boots", boots) + .build(); + } + + public void apply(LivingEntity entity, ItemRegistry itemRegistry) { + EntityEquipment equipment = entity.getEquipment(); + if (equipment == null) return; + equipment.setItemInMainHand(itemRegistry.getItem(mainHand)); + equipment.setItemInOffHand(itemRegistry.getItem(offHand)); + equipment.setHelmet(itemRegistry.getItem(helmet)); + equipment.setChestplate(itemRegistry.getItem(chestplate)); + equipment.setLeggings(itemRegistry.getItem(leggings)); + equipment.setBoots(itemRegistry.getItem(boots)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Equipment equipment = (Equipment) o; + + if (mainHand != equipment.mainHand) return false; + if (offHand != equipment.offHand) return false; + if (helmet != equipment.helmet) return false; + if (chestplate != equipment.chestplate) return false; + if (leggings != equipment.leggings) return false; + return boots == equipment.boots; + } + + @Override + public int hashCode() { + int result = mainHand; + result = 31 * result + offHand; + result = 31 * result + helmet; + result = 31 * result + chestplate; + result = 31 * result + leggings; + result = 31 * result + boots; + return result; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Extension.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Extension.java new file mode 100644 index 00000000..8aa3e87c --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Extension.java @@ -0,0 +1,112 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.BloodMobType; +import de.eldoria.bloodnight.config.ConfigCheck; +import de.eldoria.bloodnight.config.ConfigException; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Mob; + +import java.util.Objects; + +public class Extension implements ConfigCheck { + @Property(name = "", descr = "") + BloodMobType extensionType = null; + @Property(name = "", descr = "") + ExtensionRole extensionRole = null; + @Property(name = "", descr = "") + Equipment equipment = null; + @Property(name = "", descr = "") + boolean invisible = true; + @Property(name = "", descr = "") + boolean invulnerable = false; + @Property(name = "", descr = "") + boolean clearEquipment = false; + + @Override + public void check(Object data) throws ConfigException { + if (extensionRole != null && extensionType == null) { + throw new ConfigException("Extension role is set, but no extension type is present."); + } + if (extensionType != null && extensionRole == null) { + throw new ConfigException("Extension type is set, but no extension role is present."); + } + if (extensionType != null && !extensionType.entityType().getEntityClass().isInstance(Mob.class)) { + throw new ConfigException(extensionType.entityType().getEntityClass().getSimpleName() + " is not a mob."); + } + } + + public BloodMobType extensionType() { + return extensionType; + } + + public void extensionType(BloodMobType extensionType) { + this.extensionType = extensionType; + } + + public ExtensionRole extensionRole() { + return extensionRole; + } + + public void extensionRole(ExtensionRole extensionRole) { + this.extensionRole = extensionRole; + } + + public Equipment equipment() { + return equipment; + } + + public void equipment(Equipment equipment) { + this.equipment = equipment; + } + + public boolean isInvisible() { + return invisible; + } + + public void invisible(boolean invisible) { + this.invisible = invisible; + } + + public boolean isInvulnerable() { + return invulnerable; + } + + public void invulnerable(boolean invulnerable) { + this.invulnerable = invulnerable; + } + + public boolean isClearEquipment() { + return clearEquipment; + } + + public void clearEquipment(boolean clearEquipment) { + this.clearEquipment = clearEquipment; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Extension extension = (Extension) o; + + if (invisible != extension.invisible) return false; + if (invulnerable != extension.invulnerable) return false; + if (clearEquipment != extension.clearEquipment) return false; + if (extensionType != extension.extensionType) return false; + if (extensionRole != extension.extensionRole) return false; + return Objects.equals(equipment, extension.equipment); + } + + @Override + public int hashCode() { + int result = extensionType != null ? extensionType.hashCode() : 0; + result = 31 * result + (extensionRole != null ? extensionRole.hashCode() : 0); + result = 31 * result + (equipment != null ? equipment.hashCode() : 0); + result = 31 * result + (invisible ? 1 : 0); + result = 31 * result + (invulnerable ? 1 : 0); + result = 31 * result + (clearEquipment ? 1 : 0); + return result; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/ExtensionRole.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/ExtensionRole.java new file mode 100644 index 00000000..d0a9d039 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/ExtensionRole.java @@ -0,0 +1,5 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +public enum ExtensionRole { + CARRIER, PASSENGER +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobConfiguration.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobConfiguration.java new file mode 100644 index 00000000..704090e8 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobConfiguration.java @@ -0,0 +1,141 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import de.eldoria.bloodnight.bloodmob.serialization.annotation.MapProperty; +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.bloodnight.bloodmob.settings.mobsettings.BloodMobType; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting; +import de.eldoria.bloodnight.config.ConfigCheck; +import de.eldoria.bloodnight.config.ConfigException; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +public class MobConfiguration implements ConfigCheck { + @StringProperty(name = "", descr = "", pattern = "^[a-z_]+$") + String identifier; + // TODO implement type settings + @MapProperty(name = "", descr = "", key = ValueType.STRING, value = ValueType.STRING) + Map wrapTypes = new HashMap<>(); + @Property(name = "", descr = "") + Extension extension; + @Property(name = "", descr = "") + Stats stats = new Stats(); + @Property(name = "", descr = "") + Equipment equipment = new Equipment(); + @Property(name = "", descr = "") + Drops drops = new Drops(); + @Property(name = "", descr = "") + Behaviour behaviour = new Behaviour(); + + public MobConfiguration() { + } + + public MobConfiguration(String identifier) { + this.identifier = identifier.toLowerCase(Locale.ROOT); + } + + @JsonIgnore + public boolean isExtended() { + return extension != null; + } + + @Override + public void check(Object data) throws ConfigException { + if (identifier == null) throw new ConfigException("Identifier is not set."); + if (identifier.trim().isEmpty()) throw new ConfigException("Identifier is empty"); + extension.check(); + stats.check(); + drops.check(); + behaviour.check(this); + } + + public String identifier() { + return identifier; + } + + public Extension extension() { + return extension; + } + + public Stats stats() { + return stats; + } + + public Equipment equipment() { + return equipment; + } + + public Drops drops() { + return drops; + } + + public Behaviour behaviour() { + return behaviour; + } + + + public void identifier(String identifier) { + this.identifier = identifier; + } + + public void extension(Extension extension) { + this.extension = extension; + } + + public void stats(Stats stats) { + this.stats = stats; + } + + public void equipment(Equipment equipment) { + this.equipment = equipment; + } + + public void drops(Drops drops) { + this.drops = drops; + } + + public void behaviour(Behaviour behaviour) { + this.behaviour = behaviour; + } + + public Map wrapTypes() { + return wrapTypes; + } + + public void wrapTypes(Map wrapTypes) { + this.wrapTypes = wrapTypes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MobConfiguration that = (MobConfiguration) o; + + if (!Objects.equals(identifier, that.identifier)) return false; + if (!Objects.equals(wrapTypes, that.wrapTypes)) return false; + if (!Objects.equals(extension, that.extension)) return false; + if (!Objects.equals(stats, that.stats)) return false; + if (!Objects.equals(equipment, that.equipment)) return false; + if (!Objects.equals(drops, that.drops)) return false; + return Objects.equals(behaviour, that.behaviour); + } + + @Override + public int hashCode() { + int result = identifier != null ? identifier.hashCode() : 0; + result = 31 * result + (wrapTypes != null ? wrapTypes.hashCode() : 0); + result = 31 * result + (extension != null ? extension.hashCode() : 0); + result = 31 * result + (stats != null ? stats.hashCode() : 0); + result = 31 * result + (equipment != null ? equipment.hashCode() : 0); + result = 31 * result + (drops != null ? drops.hashCode() : 0); + result = 31 * result + (behaviour != null ? behaviour.hashCode() : 0); + return result; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobValueModifier.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobValueModifier.java new file mode 100644 index 00000000..89861760 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/MobValueModifier.java @@ -0,0 +1,5 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +public enum MobValueModifier { + DEFAULT, MULTIPLY, VALUE +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Stats.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Stats.java new file mode 100644 index 00000000..d0dc4158 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/Stats.java @@ -0,0 +1,89 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumericProperty; +import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property; +import de.eldoria.bloodnight.config.ConfigCheck; +import de.eldoria.bloodnight.config.ConfigException; +import lombok.Setter; + +public class Stats implements ConfigCheck { + @Setter + @Property(name = "", descr = "") + private MobValueModifier healthModifier = MobValueModifier.DEFAULT; + /** + * The max health of a mob. -1 is disabled + */ + @Setter + @NumericProperty(name = "", descr = "", max = 64) + private double health = 2; + + @Setter + @Property(name = "", descr = "") + private MobValueModifier damageModifier = MobValueModifier.DEFAULT; + /** + * The damage a mob makes. -1 is disabled + */ + @Setter + @NumericProperty(name = "", descr = "", max = 64) + private double damage = 2; + + @Override + public void check(Object data) throws ConfigException { + ConfigCheck.isNotNull(healthModifier, "health modifier"); + ConfigCheck.isNotNull(damageModifier, "damage modifier"); + ConfigCheck.isInRange(damage, -1, 1024, "damage"); + ConfigCheck.isInRange(health, -1, 1024, "health"); + } + + public double applyDamage(double baseValue, double defaultMultiplier) { + switch (damageModifier) { + case DEFAULT: + return baseValue * defaultMultiplier; + case MULTIPLY: + return baseValue * damage; + case VALUE: + return damage; + default: + throw new IllegalStateException("Unexpected value: " + damageModifier); + } + } + + public double applyHealth(double baseValue, double defaultMultiplier) { + switch (healthModifier) { + case DEFAULT: + return baseValue * defaultMultiplier; + case MULTIPLY: + return baseValue * health; + case VALUE: + return health; + default: + throw new IllegalStateException("Unexpected value: " + healthModifier); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Stats stats = (Stats) o; + + if (Double.compare(stats.health, health) != 0) return false; + if (Double.compare(stats.damage, damage) != 0) return false; + if (healthModifier != stats.healthModifier) return false; + return damageModifier == stats.damageModifier; + } + + @Override + public int hashCode() { + int result; + long temp; + result = healthModifier != null ? healthModifier.hashCode() : 0; + temp = Double.doubleToLongBits(health); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (damageModifier != null ? damageModifier.hashCode() : 0); + temp = Double.doubleToLongBits(damage); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } +} diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaDropMode.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/VanillaDropMode.java similarity index 77% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaDropMode.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/VanillaDropMode.java index 2cb529cf..53e72f9b 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/mobsettings/VanillaDropMode.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/VanillaDropMode.java @@ -1,4 +1,4 @@ -package de.eldoria.bloodnight.config.worldsettings.mobsettings; +package de.eldoria.bloodnight.bloodmob.settings; public enum VanillaDropMode { /** diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/WorldMobSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/WorldMobSettings.java new file mode 100644 index 00000000..86c3f7ea --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/WorldMobSettings.java @@ -0,0 +1,80 @@ +package de.eldoria.bloodnight.bloodmob.settings; + +import de.eldoria.bloodnight.bloodmob.drop.Drop; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class WorldMobSettings implements ConfigurationSerializable { + /** + * Enabled or disables mob names for special mobs. + */ + private boolean displayMobNames = true; + + /** + * The modifier which will be multiplied with monster damage when dealing damage to players. + */ + private double damageMultiplier = 2; + + /** + * The modifier which will be applied to special Mobs health on spawn. + */ + private double healthModifier = 2; + + /** + * The modifier which will be muliplied with the dropped exp of a monster. + */ + private double experienceMultiplier = 4; + + /** + * The general drops during blood night. + */ + private List defaultDrops = new ArrayList<>(); + + /** + * If true drops will be added to vanilla drops. If false vanilla drops will be removed. + */ + private boolean naturalDrops = true; + + /** + * Max Amount of custom drops which can be dropped on death. + */ + private int dropAmount = 3; + + @NotNull + @Override + public Map serialize() { + return null; + } + + public boolean isdisplayMobNames() { + return displayMobNames; + } + + public double damageMultiplier() { + return damageMultiplier; + } + + public double healthModifier() { + return healthModifier; + } + + public double experienceMultiplier() { + return experienceMultiplier; + } + + public List defaultDrops() { + return defaultDrops; + } + + public boolean isnaturalDrops() { + return naturalDrops; + } + + public int dropAmount() { + return dropAmount; + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/BloodMobType.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/BloodMobType.java new file mode 100644 index 00000000..9f49f945 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/BloodMobType.java @@ -0,0 +1,68 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings; + +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting.CreeperSettings; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting.PhantomSetting; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting.RabbitSettings; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting.SlimeSetting; +import org.bukkit.entity.EntityType; + +import java.util.Optional; + +public enum BloodMobType { + BAT(EntityType.BAT, TypeSetting.class), + BLAZE(EntityType.BLAZE, TypeSetting.class), + CAVE_SPIDER(EntityType.CAVE_SPIDER, TypeSetting.class), + CREEPER(EntityType.CREEPER, CreeperSettings.class), + DROWNED(EntityType.DROWNED, TypeSetting.class), + ELDER_GUARDIAN(EntityType.ELDER_GUARDIAN, TypeSetting.class), + ENDERMAN(EntityType.ENDERMAN, TypeSetting.class), + ENDERMITE(EntityType.ENDERMITE, TypeSetting.class), + EVOKER(EntityType.EVOKER, TypeSetting.class), + GHAST(EntityType.GHAST, TypeSetting.class), + GIANT(EntityType.GIANT, TypeSetting.class), + GUARDIAN(EntityType.GUARDIAN, TypeSetting.class), + HOGLIN(EntityType.HOGLIN, TypeSetting.class), + HUSK(EntityType.HUSK, TypeSetting.class), + MAGMA_CUBE(EntityType.MAGMA_CUBE, SlimeSetting.class), + PHANTOM(EntityType.PHANTOM, PhantomSetting.class), + PIGLIN(EntityType.PIGLIN, TypeSetting.class), + PIGLIN_BRUTE(EntityType.PIGLIN_BRUTE, TypeSetting.class), + RABBIT(EntityType.RABBIT, RabbitSettings.class), + SILVERFISH(EntityType.SILVERFISH, TypeSetting.class), + SKELETON(EntityType.SKELETON, TypeSetting.class), + SLIME(EntityType.SLIME, SlimeSetting.class), + SPIDER(EntityType.SPIDER, TypeSetting.class), + STRAY(EntityType.STRAY, TypeSetting.class), + STRIDER(EntityType.STRIDER, TypeSetting.class), + VEX(EntityType.VEX, TypeSetting.class), + WITCH(EntityType.WITCH, TypeSetting.class), + WITHER(EntityType.WITHER, TypeSetting.class), + WITHER_SKELETON(EntityType.WITHER_SKELETON, TypeSetting.class), + WOLF(EntityType.WOLF, TypeSetting.class), + ZOGLIN(EntityType.ZOGLIN, TypeSetting.class), + ZOMBIE(EntityType.ZOMBIE, TypeSetting.class), + ZOMBIE_VILLAGER(EntityType.ZOMBIE_VILLAGER, TypeSetting.class), + ZOMBIFIED_PIGLIN(EntityType.ZOMBIFIED_PIGLIN, TypeSetting.class); + + private final EntityType entityType; + + private final Class typeSettingClazz; + + BloodMobType(EntityType entityType, Class typeSettingClazz) { + this.entityType = entityType; + this.typeSettingClazz = typeSettingClazz; + } + + public EntityType entityType() { + return entityType; + } + + public Class typeSettingClazz() { + return typeSettingClazz; + } + + public static Optional fromEntityType(EntityType entityType) { + for (BloodMobType value : values()) if (value.entityType == entityType) return Optional.of(value); + return Optional.empty(); + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/TypeSetting.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/TypeSetting.java new file mode 100644 index 00000000..3e641a6a --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/TypeSetting.java @@ -0,0 +1,16 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.StringProperty; +import org.bukkit.entity.Mob; + +public class TypeSetting { + @StringProperty(name = "", descr = "") + String name; + + public String name() { + return name; + } + + public void apply(Mob mob) { + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/CreeperSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/CreeperSettings.java new file mode 100644 index 00000000..9289188e --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/CreeperSettings.java @@ -0,0 +1,26 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty; +import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Mob; + +public class CreeperSettings extends TypeSetting { + @Property(name = "", descr = "") + boolean powered; + @NumberProperty(name = "", descr = "", max = 64) + int maxFuseTick; + @NumberProperty(name = "", descr = "", max = 64) + int explosionRadius; + + @Override + public void apply(Mob mob) { + if (mob instanceof Creeper) { + Creeper creeper = (Creeper) mob; + creeper.setPowered(powered); + creeper.setMaxFuseTicks(maxFuseTick); + creeper.setExplosionRadius(explosionRadius); + } + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/PhantomSetting.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/PhantomSetting.java new file mode 100644 index 00000000..c97c94c0 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/PhantomSetting.java @@ -0,0 +1,18 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Phantom; + +public class PhantomSetting extends TypeSetting { + @NumberProperty(name = "", descr = "", max = 64) + private int size; + + @Override + public void apply(Mob mob) { + if(mob instanceof Phantom){ + ((Phantom) mob).setSize(size); + } + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/RabbitSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/RabbitSettings.java new file mode 100644 index 00000000..ae87feb5 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/RabbitSettings.java @@ -0,0 +1,18 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.Property; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Rabbit; + +public class RabbitSettings extends TypeSetting { + @Property(name = "", descr = "") + boolean isKiller; + + @Override + public void apply(Mob mob) { + if (mob instanceof Rabbit) { + if (isKiller) ((Rabbit) mob).setRabbitType(Rabbit.Type.THE_KILLER_BUNNY); + } + } +} diff --git a/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/SlimeSetting.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/SlimeSetting.java new file mode 100644 index 00000000..77a79566 --- /dev/null +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/mobsettings/setting/SlimeSetting.java @@ -0,0 +1,19 @@ +package de.eldoria.bloodnight.bloodmob.settings.mobsettings.setting; + +import de.eldoria.bloodnight.bloodmob.serialization.annotation.NumberProperty; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.TypeSetting; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Slime; + +public class SlimeSetting extends TypeSetting { + @NumberProperty(name = "", descr = "", max = 16) + int size; + + @Override + public void apply(Mob mob) { + if (mob instanceof Slime) { + Slime slime = (Slime) mob; + slime.setSize(size); + } + } +} diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/LightningSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/LightningSettings.java similarity index 85% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/LightningSettings.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/LightningSettings.java index 83a1680f..0d336118 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/LightningSettings.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/LightningSettings.java @@ -1,13 +1,13 @@ -package de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings; +package de.eldoria.bloodnight.bloodmob.settings.util; -import de.eldoria.bloodnight.util.InvMenuUtil; +import de.eldoria.bloodnight.config.ILightningSettings; +import de.eldoria.bloodnight.utils.InvMenuUtil; import de.eldoria.eldoutilities.serialization.SerializationUtil; import de.eldoria.eldoutilities.serialization.TypeResolvingMap; import lombok.Getter; import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -19,7 +19,7 @@ @Setter @Getter @SerializableAs("bloodNightLightningSettings") -public class LightningSettings implements ConfigurationSerializable { +public class LightningSettings implements ILightningSettings { /** * Activate Lighting. */ @@ -52,7 +52,8 @@ public LightningSettings() { } @Override - public @NotNull Map serialize() { + public @NotNull + Map serialize() { return SerializationUtil.newBuilder() .add("doLightning", doLightning) .add("lightning", lightning) diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PotionEffectSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/PotionEffectSettings.java similarity index 91% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PotionEffectSettings.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/PotionEffectSettings.java index e3490660..5559ce86 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/PotionEffectSettings.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/PotionEffectSettings.java @@ -1,4 +1,4 @@ -package de.eldoria.bloodnight.config.worldsettings.deathactions; +package de.eldoria.bloodnight.bloodmob.settings.util; import de.eldoria.eldoutilities.serialization.SerializationUtil; import de.eldoria.eldoutilities.serialization.TypeResolvingMap; @@ -28,7 +28,8 @@ public PotionEffectSettings(Map objectMap) { } @Override - public @NotNull Map serialize() { + public @NotNull + Map serialize() { return SerializationUtil.newBuilder() .add("effectType", effectType.getName()) .add("duration", duration) diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/ShockwaveSettings.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/ShockwaveSettings.java similarity index 94% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/ShockwaveSettings.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/ShockwaveSettings.java index 7d4b3fcd..e3f41981 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/config/worldsettings/deathactions/subsettings/ShockwaveSettings.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/settings/util/ShockwaveSettings.java @@ -1,6 +1,5 @@ -package de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings; +package de.eldoria.bloodnight.bloodmob.settings.util; -import de.eldoria.bloodnight.config.worldsettings.deathactions.PotionEffectSettings; import de.eldoria.eldoutilities.serialization.SerializationUtil; import de.eldoria.eldoutilities.serialization.TypeResolvingMap; import lombok.Getter; @@ -60,7 +59,8 @@ public ShockwaveSettings() { } @Override - public @NotNull Map serialize() { + public @NotNull + Map serialize() { return SerializationUtil.newBuilder() .add("shockwaveProbability", shockwaveProbability) .add("shockwavePower", shockwavePower) diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMobUtil.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/BloodMobUtil.java similarity index 88% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMobUtil.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/BloodMobUtil.java index 2ed87d9d..bfe4196a 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/SpecialMobUtil.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/BloodMobUtil.java @@ -1,18 +1,17 @@ -package de.eldoria.bloodnight.specialmobs; - -import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.LightningSettings; -import de.eldoria.bloodnight.config.worldsettings.deathactions.subsettings.ShockwaveSettings; -import de.eldoria.bloodnight.core.BloodNight; -import de.eldoria.bloodnight.specialmobs.effects.ParticleCloud; -import de.eldoria.bloodnight.specialmobs.effects.PotionCloud; -import de.eldoria.bloodnight.util.VectorUtil; +package de.eldoria.bloodnight.bloodmob.utils; + +import de.eldoria.bloodnight.bloodmob.settings.util.ShockwaveSettings; +import de.eldoria.bloodnight.config.ILightningSettings; +import de.eldoria.bloodnight.core.ABloodNight; import de.eldoria.eldoutilities.serialization.TypeConversion; import de.eldoria.eldoutilities.utils.EMath; import de.eldoria.eldoutilities.utils.ERandom; +import de.eldoria.eldoutilities.utils.VectorUtil; import org.bukkit.*; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.persistence.PersistentDataContainer; @@ -29,13 +28,13 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.logging.Level; -public final class SpecialMobUtil { - private static final NamespacedKey IS_SPECIAL_MOB = BloodNight.getNamespacedKey("isSpecialMob"); - private static final NamespacedKey IS_MOB_EXTENSION = BloodNight.getNamespacedKey("isMobExtension"); - private static final NamespacedKey BASE_UUID = BloodNight.getNamespacedKey("baseUUID"); - private static final NamespacedKey MOB_TYPE = BloodNight.getNamespacedKey("mobType"); +public final class BloodMobUtil { + private static final NamespacedKey IS_SPECIAL_MOB = ABloodNight.getNamespacedKey("isSpecialMob"); + private static final NamespacedKey IS_MOB_EXTENSION = ABloodNight.getNamespacedKey("isMobExtension"); + private static final NamespacedKey BASE_UUID = ABloodNight.getNamespacedKey("baseUUID"); + private static final NamespacedKey MOB_TYPE = ABloodNight.getNamespacedKey("mobType"); - private SpecialMobUtil() { + private BloodMobUtil() { } @Deprecated @@ -65,7 +64,19 @@ public static void spawnPotionAt(Location location, PotionEffect potionEffect, M * @param visible true if particles should be visible */ public static void addPotionEffect(LivingEntity entity, PotionEffectType type, int amplifier, boolean visible) { - entity.addPotionEffect(new PotionEffect(type, 60 * 20, amplifier, visible, visible)); + addPotionEffect(entity, type, 60, amplifier, visible); + } + + /** + * Adds a simple potion effect to a entitiy. + * + * @param entity entity to add potion effect + * @param type type of potion effect + * @param amplifier amplifier + * @param visible true if particles should be visible + */ + public static void addPotionEffect(LivingEntity entity, PotionEffectType type, int seconds, int amplifier, boolean visible) { + entity.addPotionEffect(new PotionEffect(type, seconds * 20, amplifier, visible, visible)); } /** @@ -358,7 +369,7 @@ public static void dispatchShockwave(ShockwaveSettings settings, Location locati double power = settings.getPower(directionVector); Vector normalize = directionVector.clone().normalize(); if (Math.abs(normalize.getY()) <= 0.1) { - BloodNight.logger().log(Level.FINE, "Adjusting shockwave direction. Vector is too flat."); + ABloodNight.logger().log(Level.FINE, "Adjusting shockwave direction. Vector is too flat."); normalize.add(new Vector(0, 0.1, 0)); } normalize.multiply(power); @@ -366,14 +377,14 @@ public static void dispatchShockwave(ShockwaveSettings settings, Location locati continue; } normalize.setY(EMath.clamp(-0.2, 0.2, normalize.getY())); - BloodNight.logger().log(Level.FINE, "Launching entity in direction " + normalize.toString() + ABloodNight.logger().log(Level.FINE, "Launching entity in direction " + normalize.toString() + " | Power: " + power + " | Initial direction: " + directionVector); entity.setVelocity(normalize); settings.applyEffects(entity, power); } } - public static void dispatchLightning(LightningSettings settings, Location location) { + public static void dispatchLightning(ILightningSettings settings, Location location) { if (location.getWorld() == null) return; if (settings.isDoLightning() && settings.getLightning() != 0) { if (ThreadLocalRandom.current().nextInt(101) <= settings.getLightning()) { @@ -426,4 +437,15 @@ public static PotionCloud.Builder buildPotionCloud(LivingEntity target) { public static PotionCloud.Builder buildParticleCloud(Location location) { return PotionCloud.builder(location); } + + public static void clearEquipment(LivingEntity entity) { + EntityEquipment equipment = entity.getEquipment(); + if (equipment == null) return; + equipment.setItemInMainHand(null); + equipment.setItemInOffHand(null); + equipment.setHelmet(null); + equipment.setChestplate(null); + equipment.setLeggings(null); + equipment.setBoots(null); + } } diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/ParticleCloud.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/ParticleCloud.java similarity index 97% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/ParticleCloud.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/ParticleCloud.java index 33806204..90c3e13a 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/ParticleCloud.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/ParticleCloud.java @@ -1,4 +1,4 @@ -package de.eldoria.bloodnight.specialmobs.effects; +package de.eldoria.bloodnight.bloodmob.utils; import lombok.Getter; import org.bukkit.Color; @@ -67,7 +67,6 @@ public Builder withParticle(@NotNull Particle particle, @Nullable T data) { return this; } - public ParticleCloud build() { return new ParticleCloud(entity); } diff --git a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/PotionCloud.java b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/PotionCloud.java similarity index 98% rename from BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/PotionCloud.java rename to BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/PotionCloud.java index 4739f7d5..4f853032 100644 --- a/BloodNight-core/src/main/java/de/eldoria/bloodnight/specialmobs/effects/PotionCloud.java +++ b/BloodNight-mobs/src/main/java/de/eldoria/bloodnight/bloodmob/utils/PotionCloud.java @@ -1,4 +1,4 @@ -package de.eldoria.bloodnight.specialmobs.effects; +package de.eldoria.bloodnight.bloodmob.utils; import org.bukkit.Color; import org.bukkit.Location; diff --git a/BloodNight-web/README.md b/BloodNight-web/README.md new file mode 100644 index 00000000..aaa8ac84 --- /dev/null +++ b/BloodNight-web/README.md @@ -0,0 +1,942 @@ +# BloodNight Web Service + +# Mob Editor + +The mob editor is available on route: + +``` +/v1/mobEditor +``` + +## Sessions + +In order to start working with the mob editor api you need to open a session. These sessions hold and provide data. + +### Open Session + +``` +POST /v1/mobeditor/submit +``` + +Open a session. + +The payload has to be a `MobEditorPayload`. + +The request will return a `access token` and a `201` code if the session was created successfully. + +The session will stay open as long as any interaction is made on the session in the last hour. After this the session +data gets deleted. + +From now on all request have to be made with the access token in a `token` header. + + +
+Example + +`POST /v1/mobeditor/submit` + +```json +{ + "settingsContainer": { + "configurations": [ + { + "identifier": "test_mob", + "wrapTypes": {}, + "extension": null, + "stats": { + "healthModifier": "DEFAULT", + "health": 2.0, + "damageModifier": "DEFAULT", + "damage": 2.0 + }, + "equipment": { + "mainHand": -1, + "offHand": -1, + "helmet": -1, + "chestplate": -1, + "leggings": -1, + "boots": -1 + }, + "drops": { + "minDrops": -1, + "maxDrops": -1, + "overrideDefaultDrops": false, + "drops": [] + }, + "behaviour": { + "behaviourMap": { + "ON_HIT": [], + "ON_EXPLOSION": [], + "ON_PROJECTILE_SHOOT": [], + "ON_DAMAGE": [], + "ON_PROJECTILE_HIT": [], + "ON_DEATH": [], + "ON_END": [], + "TICK": [ + { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.mapper.MoveToLocation", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.PredicateFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion", + "type": "BLINDNESS", + "seconds": 20, + "amplifier": 2, + "visible": true + }, + "duration": 10 + }, + "invert": false, + "predicate": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.HasTarget" + } + }, + "source": "OLD" + } + ], + "ON_EXPLOSION_PRIME": [], + "ON_TARGET": [], + "ON_TELEPORT": [], + "ON_DAMAGE_BY_ENTITY": [ + { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.mapper.MoveToLocation", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.PredicateFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion", + "type": "BLINDNESS", + "seconds": 20, + "amplifier": 2, + "visible": true + }, + "duration": 10 + }, + "invert": false, + "predicate": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.HasTarget" + } + }, + "source": "OLD" + } + ], + "ON_KILL": [ + { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.mapper.MoveToLocation", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.PredicateFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter", + "nextNode": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion", + "type": "BLINDNESS", + "seconds": 20, + "amplifier": 2, + "visible": true + }, + "duration": 10 + }, + "invert": false, + "predicate": { + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.predicate.HasTarget" + } + }, + "source": "OLD" + } + ] + } + } + } + ], + "items": [ + { + "id": 0, + "type": "DIAMOND_BOOTS", + "enchantment": { + "unbreaking": 3 + }, + "lore": [], + "displayName": null + }, + { + "id": 1, + "type": "DIAMOND_CHESTPLATE", + "enchantment": {}, + "lore": [ + "This is", + "a nice", + "Lore" + ], + "displayName": null + } + ], + "globalDrops": [ + { + "itemId": 0, + "amount": 5, + "weight": 10 + }, + { + "itemId": 0, + "amount": 2, + "weight": 10 + }, + { + "itemId": 2, + "amount": 12, + "weight": 80 + } + ] + } +} +``` + +
+ +### Close a session + +``` +POST /v1/mobeditor/close +``` + +Close the current session. + +If the session is not closed yet it will be closed and a `200` code will be returned with a retreival token. This token +can be only retrieved once. + +Data of a closed session will be deleted 30 minutes after the last access. + +### Retrieve Data + +``` +GET /v1/mobeditor/retrieve/:token +``` + +Retrieve the settings from the web server. The `:token` has to be the token returned by the `/v1/mobeditor/close` +endpoint. + +## Types + +The api uses specific types for fields. + +### Typelist + +``` +GET /v1/mobeditor/types +``` + +Returns all available types including a class description if available. + +If no class description is available the value will be null. + + +
+Example + +```json +{ + "MULTI_LIST": null, + "DROPS": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Drops", + "values": [ + { + "field": "minDrops", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": -1, + "max": 64 + } + }, + { + "field": "maxDrops", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": -1, + "max": 64 + } + }, + { + "field": "overrideDefaultDrops", + "name": "", + "descr": "", + "type": "BOOLEAN" + }, + { + "field": "drops", + "name": "", + "descr": "", + "type": "LIST", + "values": [ + { + "field": "itemId", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "amount", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": 0, + "max": 64 + } + }, + { + "field": "weight", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": 0, + "max": 100 + } + } + ] + } + ] + }, + "NUMBER": null, + "NUMERIC": null, + "BEHAVIOUR": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Behaviour", + "values": [] + }, + "STATS": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Stats", + "values": [ + { + ... + } + ] + }, + "PREDICATE": { + "clazz": "de.eldoria.bloodnight.bloodmob.node.predicate.PredicateNode", + "values": [] + }, + "EXTENSION": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Extension", + "values": [ + { + "field": "extensionType", + "name": "", + "descr": "", + "type": "LIST", + "values": [ + "BAT", + "BLAZE", + "CAVE_SPIDER", + "CREEPER", + ... + "WOLF", + "ZOGLIN", + "ZOMBIE", + "ZOMBIE_VILLAGER", + "ZOMBIFIED_PIGLIN" + ] + }, + { + "field": "extensionRole", + "name": "", + "descr": "", + "type": "LIST", + "values": [ + "CARRIER", + "PASSENGER" + ] + }, + { + "field": "equipment", + "name": "", + "descr": "", + "type": "EQUIPMENT" + }, + { + "field": "invisible", + "name": "", + "descr": "", + "type": "BOOLEAN" + }, + { + "field": "invulnerable", + "name": "", + "descr": "", + "type": "BOOLEAN" + }, + { + "field": "clearEquipment", + "name": "", + "descr": "", + "type": "BOOLEAN" + } + ] + }, + "BOOLEAN": null, + "DROP": { + "clazz": "de.eldoria.bloodnight.bloodmob.drop.Drop", + "values": [ + { + "field": "itemId", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "amount", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": 0, + "max": 64 + } + }, + { + "field": "weight", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": 0, + "max": 100 + } + } + ] + }, + "ITEM": { + "clazz": "de.eldoria.bloodnight.bloodmob.registry.items.SimpleItem", + "values": [ + { + "field": "id", + "name": "", + "descr": "", + "type": "NUMBER", + "values": { + "min": 0, + "max": 2147483647 + } + }, + { + "field": "type", + "name": "", + "descr": "", + "type": "STRING", + "values": { + "pattern": "", + "min": 0, + "max": 32 + } + }, + { + "field": "enchantment", + "name": "", + "descr": "", + "type": "MAP", + "values": { + "keys": { + "type": "STRING" + }, + "value": { + "type": "NUMBER" + } + } + }, + { + "field": "lore", + "name": "", + "descr": "", + "type": "LIST", + "values": [] + }, + { + "field": "displayName", + "name": "", + "descr": "", + "type": "STRING", + "values": { + "pattern": "", + "min": 0, + "max": 32 + } + } + ] + }, + "EQUIPMENT": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Equipment", + "values": [ + { + "field": "mainHand", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "offHand", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "helmet", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "chestplate", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "leggings", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "boots", + "name": "", + "descr": "", + "type": "ITEM" + } + ] + }, + "COLOR": null, + "STRING": null, + "LIST": null, + "MAP": null +} +``` + +
+ +### Type + +``` +GET /v1/mobeditor/type/:type +``` + +Returns the class description of the type if available. + +If no class description is available the value will be `null`. + +```json +{ + +} +``` + +## Moblist + +``` +GET /v1/mobeditor/moblist +``` + +Returns a list of identifiers of all available mobs + +## MobSettings + +Mobs can be created, retreived or deleted by the `mobSettings` endpoint: + +``` +/v1/mobeditor/mobsettings/:identifier +``` + +The `:identifier` is the identifier of the mob. + +### Retrieve Mob Settings + +``` +GET /v1/mobeditor/mobsettings/:identifier +``` + +Retrieve the mob settings. Probably not needed. Use the more specific endpoint if possible. + +### Create Mob Setting + +``` +POST /v1/mobeditor/mobsettings/:identifier +``` + +Create a new mob with a identifier. + +Returns `201` if the mob was created. + +### Delete Mob Setting + +``` +DELETE /v1/mobeditor/mobsettings/:identifier +``` + +Deletes the mob with a identifier. + +Returns `202` if the mob was deleted. + +## Change Settings + +All changes for a specific mob start at this endpoint + +``` +/v1/mobeditor/mobsettings/:identifier +``` + +### Define mob wrapper types + +Wrap types define which mobs types can be wrapped to this mob. + +#### Get available types + +``` +GET /v1/mobeditor/mobsettings/:identifier/wraptypes/available +``` + +Returns all available wrap types, which are not already present as wrap type. + +These types contain a class description for the wrapper type. + +```json +{ + "type": { + + } +} +``` + +#### Get set types + +``` +GET /v1/mobeditor/mobsettings/:identifier/wraptypes/available +``` + +Returns all wrap types which are set alreay. They will be returned as a `DataDescriptionContainer` + +```json +{ + "type": { + "data": { + ... + }, + "definition": { + ... + } + } +} +``` + +#### Delete wrapp type + +``` +DELETE /v1/mobeditor/mobsettings/:identifier/wraptypes/:type +``` + +Delete the wrapper type. Returns `202` if the wrapper type was deleted. + +#### Add wrap type + +``` +PUT /v1/mobeditor/mobsettings/:identifier/wraptypes/:type +``` + +Add a new wrap type. Can override currently existing types. + +The body should contain an object like defined from the endpoints in the two sections above. + +`PUT /v1/mobeditor/mobsetting/test_mob/wraptypes/SLIME` + +```json +{ + "size": 1, + "name": "Slime" +} +``` + +### Settings + +Settings are provided via keys: + +``` +extension +extension.equipment +equipment +drops +behaviour +``` + +These keys represent the names of the fields returned by the settings endpoint above. + +Changes on the behaviour system have an own endpoint. + +#### Get the current settings + +``` +GET /v1/mobeditor/mobsettings/:identifier/settings/:setting +``` + +Get the current setting of a setting and the description of the setting. + + +
+Example + +`GET /v1/mobeditor/mobsetting/test_mob/equipment` + +```json +{ + "data": { + "mainHand": -1, + "offHand": -1, + "helmet": -1, + "chestplate": -1, + "leggings": -1, + "boots": -1 + }, + "definition": { + "clazz": "de.eldoria.bloodnight.bloodmob.settings.Equipment", + "values": [ + { + "field": "mainHand", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "offHand", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "helmet", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "chestplate", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "leggings", + "name": "", + "descr": "", + "type": "ITEM" + }, + { + "field": "boots", + "name": "", + "descr": "", + "type": "ITEM" + } + ] + } +} + +``` + +
+ +#### Set the settings + +``` +PUT /v1/mobeditor/mobsettings/:identifier/settings/:setting +``` + +Set the current setting of a setting. + +The setting should be of the format like descriped by the data description provided by the endpoint above + + +
+Example + +`http://localhost:8888/v1/mobeditor/mobsetting/test_mob/equipment` + +```json +{ + "mainHand": 1, + "offHand": 2, + "helmet": 3, + "chestplate": 4, + "leggings": 5, + "boots": 6 +} +``` + +
+ +## Behaviour + +The behaviour system is defined at the endpoint: + +``` +/v1/mobeditor/mobsettings/:identifier/behaviour/node/:type +``` + +Nodes are sorted by types. Each type has a list of node chains. A node chain can be accessed by its index. + +### Get next Nodes + +``` +GET /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type/nextNodes +``` + +Returns possible nodes for this specific type as class description + +``` +GET /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type/:id/nextNodes +``` + +Returns possible nodes for the node chain with `id` of `type` as class description + +### Add node + +``` +PUT /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type/:id +``` + +Add a new node to the node chain + + +
+Example + +`PUT /v1/mobeditor/mobsetting/test_mob/behaviour/node/TICK/1` + +```json +{ + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.action.LaunchProjectileOnTarget", + "projectileType": "LARGE_FIREBALL", + "speed": 5 +} +``` + +
+ +Returns 201 when the node was created. + +Returns 304 if the chain is already closed. + +### Create node + +``` +PUT /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type +``` + +Create a new node chain with a type. + + +
+Example + +`PUT /v1/mobeditor/mobsetting/test_mob/behaviour/node/TICK` + +```json +{ + "clazz": "de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter", + "duration": 10 +} +``` + +
+ +Returns 201 and the id of the created chain + +### Remove last node + +``` +DELETE /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type/:id/last +``` + +Removes the last node in a chain. The last node cant be removed. Delete the chain instead + +### Delete node chain + +``` +DELETE /v1/mobeditor/mobsettings/:identifier/behaviour/node/:type/:id +``` + +Delete the node chain. + +### Get types + +``` +GET /v1/mobeditor/mobsetting/:identifier/behaviour/node/types +``` + +Get available event types + +### Get Chain + +``` +GET /v1/mobeditor/mobsetting/:identifier/behaviour/node/:type/:id +``` + +Get the current chain with description + +### Get Nodes + +``` +GET /v1/mobeditor/mobsetting/:identifier/behaviour/node/nodes +``` + +Get the node types with nodes + +### Get Nodes + +``` +GET /v1/mobeditor/mobsetting/:identifier/behaviour/node/nodes +``` + +Get Nodes of a specific type. + +# Global Drops + +## Get Drops +``` +GET /v1/mobeditor/globaldrops +``` + +Get a list of global drops + +## Delete Drop +``` +DELETE /v1/mobeditor/globaldrops +``` + +Delete a drop by sending the drop to delete in the body. + +Returns 202 if the drop was removed or 304 if the drop does not exists. + +# Class definitions + +Class definitions are used very often. They describe the class and the fields in it: + +```json +{ + "type": "fully qualified name of clazz", + "name": "Human readable translated name of clazz", + "description": "description of clazz", + "values": [ + { + "field": "name of field", + "name": "human readable name of field", + "description": "Description of field", + "type": "type of the field", + "values": { + "Depends on the type. May be a integer range, a list of valid values or other stuff. Can be empty as well" + } + } + ] +} +``` \ No newline at end of file diff --git a/BloodNight-web/build.gradle.kts b/BloodNight-web/build.gradle.kts new file mode 100644 index 00000000..a72afc5b --- /dev/null +++ b/BloodNight-web/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + java + id("de.eldoria.library-conventions") + id("com.github.johnrengelman.shadow") version "7.0.0" +} + +description = "BloodNight-api" +val log4jVersion = "2.14.0" + +java { + sourceCompatibility = JavaVersion.VERSION_15 +} + +dependencies { + api(project(":BloodNight-mobs")) + implementation("org.spigotmc", "spigot-api", "1.16.5-R0.1-SNAPSHOT") + implementation("com.sparkjava", "spark-core", "2.9.3") + implementation("org.apache.logging.log4j", "log4j-core", log4jVersion) + implementation("org.apache.logging.log4j", "log4j-slf4j-impl", log4jVersion) +} + +tasks { + shadowJar { + mergeServiceFiles() + manifest { + attributes(mapOf("Main-Class" to "de.eldoria.bloodnight.webservice.WebService")) + } + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/ClassDefinition.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/ClassDefinition.java new file mode 100644 index 00000000..e4dcb43b --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/ClassDefinition.java @@ -0,0 +1,48 @@ +package de.eldoria.bloodnight.serialization; + +import de.eldoria.bloodnight.bloodmob.serialization.PropertyGenerator; +import de.eldoria.bloodnight.bloodmob.serialization.value.SimpleValue; +import de.eldoria.eldoutilities.container.Pair; + +import java.util.List; +import java.util.stream.Collectors; + +public class ClassDefinition { + private String clazz; + private String name; + private String description; + private List values; + + public ClassDefinition(Class clazz, String name, String description, List values) { + this.clazz = clazz.getName(); + this.name = name; + this.description = description; + this.values = values; + } + + public static ClassDefinition of(Class clazz) { + var values = PropertyGenerator.generateValues(clazz); + var classProperty = PropertyGenerator.getClassProperty(clazz); + return new ClassDefinition(clazz, classProperty.first, classProperty.second, values); + } + + public static List of(List> clazz) { + return clazz.stream().map(ClassDefinition::of).collect(Collectors.toList()); + } + + public String clazz() { + return clazz; + } + + public List values() { + return values; + } + + public String name() { + return name; + } + + public String description() { + return description; + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/DataDescriptionContainer.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/DataDescriptionContainer.java new file mode 100644 index 00000000..bd1b47b3 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/DataDescriptionContainer.java @@ -0,0 +1,23 @@ +package de.eldoria.bloodnight.serialization; + +public class DataDescriptionContainer { + Data data; + T definition; + + public DataDescriptionContainer(Data object, T of) { + data = object; + definition = of; + } + + public static DataDescriptionContainer of(Data object) { + return new DataDescriptionContainer<>(object, ClassDefinition.of(object.getClass())); + } + + public static DataDescriptionContainer of(Data object, Class clazz) { + return new DataDescriptionContainer<>(object, ClassDefinition.of(clazz)); + } + + public static DataDescriptionContainer of(Data object, T definition) { + return new DataDescriptionContainer<>(object, definition); + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/NodeData.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/NodeData.java new file mode 100644 index 00000000..5f32e169 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/serialization/NodeData.java @@ -0,0 +1,39 @@ +package de.eldoria.bloodnight.serialization; + +import de.eldoria.bloodnight.bloodmob.node.Node; +import de.eldoria.bloodnight.bloodmob.serialization.value.SimpleValue; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class NodeData { + Map> definitions; + Node startNode; + + public NodeData(Node startNode, Map> definitions) { + this.startNode = startNode; + this.definitions = definitions; + } + + public NodeData(){ + + } + + + public static NodeData of(Node node) { + var definitions = node.getClasses(new HashSet<>()).stream() + .map(ClassDefinition::of) + .collect(Collectors.toMap(ClassDefinition::clazz, ClassDefinition::values)); + return new NodeData(node, definitions); + } + + public Map> definitions() { + return definitions; + } + + public Node startNode() { + return startNode; + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/util/ClassDefintionUtil.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/util/ClassDefintionUtil.java new file mode 100644 index 00000000..8bbfe7fc --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/util/ClassDefintionUtil.java @@ -0,0 +1,25 @@ +package de.eldoria.bloodnight.util; + +import de.eldoria.bloodnight.bloodmob.settings.Behaviour; +import de.eldoria.bloodnight.serialization.ClassDefinition; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class ClassDefintionUtil { + public static List getBehaviourDefinitions(Behaviour behaviour) { + return behaviour.behaviourMap() + .values() + .stream() + .map(nodeList -> nodeList.stream() + .flatMap(node -> node.getClasses(new HashSet<>()).stream()) + .collect(Collectors.toSet())) + .flatMap(Set::stream) + .collect(Collectors.toSet()) + .stream() + .map(ClassDefinition::of) + .collect(Collectors.toList()); + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/SessionService.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/SessionService.java new file mode 100644 index 00000000..13904dca --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/SessionService.java @@ -0,0 +1,68 @@ +package de.eldoria.bloodnight.webservice; + +import de.eldoria.bloodnight.webservice.sessions.Session; +import org.eclipse.jetty.http.HttpStatus; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static spark.Spark.halt; + +public class SessionService implements Runnable { + private final Map> openSessions = new HashMap<>(); + private final Map> closedSessions = new HashMap<>(); + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + + private SessionService() { + } + + public static SessionService create() { + var sessionService = new SessionService(); + sessionService.init(); + return sessionService; + } + + private void init() { + executorService.scheduleAtFixedRate(this, 15, 15, TimeUnit.MINUTES); + } + + public Session openSession(T data) { + var session = new Session<>(data); + openSessions.put(session.accessToken(), session); + return session; + } + + + public Session getSession(String token) { + if (!openSessions.containsKey(token)) halt(HttpStatus.UNAUTHORIZED_401, "Invalid Session"); + var session = openSessions.get(token); + if (session.isClosed()) halt(HttpStatus.FORBIDDEN_403, "Session is closed."); + return session; + } + + public Session getClosedSession(String token) { + if (!closedSessions.containsKey(token)) halt(HttpStatus.UNAUTHORIZED_401); + return closedSessions.get(token); + } + + public Session closeSession(Session session) { + session.close(); + closedSessions.put(session.retrievaltoken(), openSessions.remove(session.accessToken())); + return session; + } + + @Override + public void run() { + openSessions.entrySet().removeIf(next -> next.getValue().lastActive().isBefore(Instant.now().minus(60, ChronoUnit.MINUTES))); + closedSessions.entrySet().removeIf(next -> next.getValue().lastActive().isBefore(Instant.now().minus(30, ChronoUnit.MINUTES))); + } + + public void forceSession(String token, Session session) { + openSessions.put(token, session); + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/WebService.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/WebService.java new file mode 100644 index 00000000..f8608a15 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/WebService.java @@ -0,0 +1,118 @@ +package de.eldoria.bloodnight.webservice; + +import de.eldoria.bloodnight.webservice.configuration.Configuration; +import de.eldoria.bloodnight.webservice.modules.mobeditor.MobEditorService; +import org.slf4j.Logger; + +import java.io.IOException; +import java.util.stream.Collectors; + +import static org.slf4j.LoggerFactory.getLogger; +import static spark.Spark.before; +import static spark.Spark.delete; +import static spark.Spark.get; +import static spark.Spark.ipAddress; +import static spark.Spark.options; +import static spark.Spark.path; +import static spark.Spark.port; +import static spark.Spark.post; +import static spark.Spark.put; + +public class WebService { + private static WebService instance; + private final MobEditorService mobEditorService = new MobEditorService(); + private Configuration configuration; + + private static final Logger log = getLogger(WebService.class); + + public static void main(String[] args) throws IOException { + WebService.instance = new WebService(); + instance.ignite(); + } + + private void ignite() throws IOException { + configuration = Configuration.load(); + port(configuration.general().port()); + ipAddress(configuration.general().host()); + + options("/*", (request, response) -> { + var accessControlRequestHeaders = request + .headers("Access-Control-Request-Headers"); + if (accessControlRequestHeaders != null) { + response.header("Access-Control-Allow-Headers", + "token"); + } + + var accessControlRequestMethod = request + .headers("Access-Control-Request-Method"); + if (accessControlRequestMethod != null) { + response.header("Access-Control-Allow-Methods", + "HEAD, GET, DELETE, PATCH, POST, OPTIONS"); + } + + return "OK"; + }); + + before((request, response) -> { + log.trace("Received request on route: {} {}\nHeaders:\n{}\nBody:\n{}", + request.requestMethod() + " " + request.uri(), + request.queryString(), + request.headers().stream().map(h -> " " + h + ": " + request.headers(h)) + .collect(Collectors.joining("\n")), + request.body().substring(0, Math.min(request.body().length(), 180))); + response.header("Access-Control-Allow-Origin", "*"); + response.header("Access-Control-Allow-Headers", "*"); + }); + + + path("/" + configuration.general().apiRoot() + "/v1", () -> { + path("/mobeditor", () -> { + post("/submit", mobEditorService::submit); + post("/close", mobEditorService::close); + get("/retrieve/:token", mobEditorService::retrieve); + + get("/types", mobEditorService::getTypes); + get("/type/:type", mobEditorService::getType); + + get("/moblist", mobEditorService::mobList); + + path("/mobsetting", () -> { + + get("/:identifier", mobEditorService::getMobSettings); + post("/:identifier", mobEditorService::createMobSettings); + delete("/:identifier", mobEditorService::deleteMobSettings); + + path("/:identifier", () -> { + get("/wraptypes/available", mobEditorService::getaAvailableTypes); + get("/wraptypes/set", mobEditorService::getSetWrapTypes); + delete("/wraptypes/:type", mobEditorService::removeWrapType); + put("/wraptypes/:type", mobEditorService::addWrapType); + + get("/:setting", mobEditorService::getSetting); + put("/:setting", mobEditorService::setSetting); + + path("/behaviour", () -> { + path("/node", () -> { + get("/types", mobEditorService::getEventTypes); + get("/nodes/:type", mobEditorService::getNodeType); + get("/nodes", mobEditorService::getNodeTypes); + get("/:type/nextNodes", mobEditorService::nextTypeNodes); + put("/:type", mobEditorService::createNode); + put("/:type/:id", mobEditorService::addNode); + delete("/:type/:id/last", mobEditorService::removeLastNode); + delete("/:type/:id", mobEditorService::deleteNode); + get("/:type/:id/nextNodes", mobEditorService::nextNodes); + get("/:type/:id", mobEditorService::getChain); + }); + }); + }); + }); + + get("/items", mobEditorService::getItems); + delete("/items/:id", mobEditorService::deleteItem); + get("/globaldrops", mobEditorService::getGlobalDrops); + delete("/globaldrops", mobEditorService::removeGlobalDrop); + }); + }); + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/Configuration.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/Configuration.java new file mode 100644 index 00000000..7d729d53 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/Configuration.java @@ -0,0 +1,72 @@ +package de.eldoria.bloodnight.webservice.configuration; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import de.eldoria.bloodnight.webservice.configuration.elements.General; +import org.slf4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.slf4j.LoggerFactory.getLogger; + +public class Configuration { + private static final Logger log = getLogger(Configuration.class); + private static final ObjectMapper MAPPER = new ObjectMapper() + .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) + .setDefaultPrettyPrinter(new DefaultPrettyPrinter()) + .configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true); + private General general = new General(); + + private Configuration() { + } + + public void reload() throws IOException, ConfigurationException { + var configuration = load(); + general = configuration.general; + save(); + } + + public void save() throws IOException { + try (var writer = MAPPER.writerWithDefaultPrettyPrinter().writeValues(getConfig().toFile())) { + writer.write(this); + } + } + + public static Configuration load() throws IOException, ConfigurationException { + forceConsistency(); + var configuration = MAPPER.readValue(getConfig().toFile(), Configuration.class); + configuration.save(); + return configuration; + } + + private static void forceConsistency() throws IOException { + Files.createDirectories(getConfig().getParent()); + if (!getConfig().toFile().exists()) { + if (getConfig().toFile().createNewFile()) { + MAPPER.writerWithDefaultPrettyPrinter().writeValues(getConfig().toFile()).write(new Configuration()); + throw new ConfigurationException("Please configure the config."); + } + } + } + + private static Path getConfig() { + var home = new File(".").getAbsoluteFile().getParentFile().toPath(); + var property = System.getProperty("config"); + if (property == null) { + log.error("bot.config property is not set."); + throw new ConfigurationException("Property -Dconfig= is not set."); + } + return Paths.get(home.toString(), property); + } + + public General general() { + return general; + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/ConfigurationException.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/ConfigurationException.java new file mode 100644 index 00000000..32565b5d --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/ConfigurationException.java @@ -0,0 +1,7 @@ +package de.eldoria.bloodnight.webservice.configuration; + +public class ConfigurationException extends RuntimeException { + public ConfigurationException(String message) { + super(message); + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/elements/General.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/elements/General.java new file mode 100644 index 00000000..c1acb32e --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/configuration/elements/General.java @@ -0,0 +1,19 @@ +package de.eldoria.bloodnight.webservice.configuration.elements; + +public class General { + String apiRoot = "api"; + String host = "0.0.0.0"; + int port = 8888; + + public String host() { + return host; + } + + public int port() { + return port; + } + + public String apiRoot() { + return apiRoot; + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/InvalidSessionException.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/InvalidSessionException.java new file mode 100644 index 00000000..f8045d75 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/InvalidSessionException.java @@ -0,0 +1,4 @@ +package de.eldoria.bloodnight.webservice.exceptions; + +public class InvalidSessionException extends SessionException{ +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionClosedException.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionClosedException.java new file mode 100644 index 00000000..70e33dcb --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionClosedException.java @@ -0,0 +1,4 @@ +package de.eldoria.bloodnight.webservice.exceptions; + +public class SessionClosedException extends SessionException{ +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionException.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionException.java new file mode 100644 index 00000000..7b3f5071 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/exceptions/SessionException.java @@ -0,0 +1,4 @@ +package de.eldoria.bloodnight.webservice.exceptions; + +public class SessionException extends Exception{ +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/MobEditorService.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/MobEditorService.java new file mode 100644 index 00000000..dda89084 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/MobEditorService.java @@ -0,0 +1,434 @@ +package de.eldoria.bloodnight.webservice.modules.mobeditor; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.net.MediaType; +import de.eldoria.bloodnight.bloodmob.drop.Drop; +import de.eldoria.bloodnight.bloodmob.node.Node; +import de.eldoria.bloodnight.bloodmob.node.NodeHolder; +import de.eldoria.bloodnight.bloodmob.node.contextcontainer.ContextContainerFactory; +import de.eldoria.bloodnight.bloodmob.registry.NodeRegistry; +import de.eldoria.bloodnight.bloodmob.serialization.container.MobEditorPayload; +import de.eldoria.bloodnight.bloodmob.serialization.mapper.MobMapper; +import de.eldoria.bloodnight.bloodmob.serialization.value.ValueType; +import de.eldoria.bloodnight.bloodmob.settings.BehaviourNodeType; +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.MobConfiguration; +import de.eldoria.bloodnight.bloodmob.settings.mobsettings.BloodMobType; +import de.eldoria.bloodnight.serialization.ClassDefinition; +import de.eldoria.bloodnight.serialization.DataDescriptionContainer; +import de.eldoria.bloodnight.util.ClassDefintionUtil; +import de.eldoria.bloodnight.webservice.WebService; +import de.eldoria.bloodnight.webservice.sessions.Session; +import de.eldoria.eldoutilities.container.Triple; +import de.eldoria.eldoutilities.utils.EnumUtil; +import org.eclipse.jetty.http.HttpStatus; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import spark.Request; +import spark.Response; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.slf4j.LoggerFactory.getLogger; +import static spark.Spark.halt; + +public class MobEditorService extends SessionHolder { + private static final Logger log = getLogger(MobEditorService.class); + + public Object submit(Request request, Response response) { + var mobEditorPayload = readInput(request, MobEditorPayload.class); + var session = openSession(mobEditorPayload); + return respondStatus(response, HttpStatus.CREATED_201, session.accessToken()); + } + + public Object close(Request request, Response response) { + var session = getSession(request, response); + session = closeSession(session); + return respondStatus(response, HttpStatus.OK_200, session.retrievaltoken()); + } + + public Object retrieve(Request request, Response response) { + var closedSession = getClosedSession(request, response); + return writeJsonResponse(response, closedSession.sessionData()); + } + + public Object getTypes(Request request, Response response) { + Map classDefinition = new HashMap<>(); + for (var value : ValueType.values()) { + classDefinition.put(value.name(), value.clazz() == null ? null : ClassDefinition.of(value.clazz())); + } + return writeJsonResponse(response, classDefinition); + } + + public Object getType(Request request, Response response) { + var parse = EnumUtil.parse(request.params(":type"), ValueType.class); + if (parse == null) { + halt(HttpStatus.BAD_REQUEST_400, "Invalid type"); + } + + if (parse.clazz() != null) { + return writeJsonResponse(response, ClassDefinition.of(parse.clazz())); + } + return respondStatus(response, HttpStatus.NO_CONTENT_204); + } + + public Object mobList(Request request, Response response) { + var session = getSession(request, response); + var identifier = session.readData(data -> data.settingsContainer().mobIdentifier()); + + return writeJsonResponse(response, identifier); + } + + public Object getMobSettings(Request request, Response response) { + var configuration = getSessionMobSettings(request, response); + return writeJsonResponse(response, DataDescriptionContainer.of(configuration)); + } + + public Object createMobSettings(Request request, Response response) { + var session = getSession(request, response); + var identifier = request.params(":identifier"); + var mobEditorPayload = session.sessionData(); + if (mobEditorPayload.settingsContainer().mobExists(identifier)) { + halt(HttpStatus.CONFLICT_409, "Identifier already in use."); + } + + mobEditorPayload.settingsContainer().createMob(identifier); + return respondCreated(response); + } + + public Object deleteMobSettings(Request request, Response response) { + var session = getSession(request, response); + var identifier = request.params(":identifier"); + var mobEditorPayload = session.sessionData(); + + var removed = mobEditorPayload.settingsContainer().removeMob(identifier); + + if (!removed) halt(HttpStatus.NOT_MODIFIED_304, "Identifier not found."); + + return respondAccepted(response); + } + + public Object getaAvailableTypes(Request request, Response response) { + Map definitions = new HashMap<>(); + + var mobSettings = getSessionMobSettings(request, response); + + for (var value : BloodMobType.values()) { + if (mobSettings.wrapTypes().containsKey(value)) continue; + definitions.put(value, ClassDefinition.of(value.typeSettingClazz())); + } + return writeJsonResponse(response, definitions); + } + + public Object getSetWrapTypes(Request request, Response response) { + Map> definitions = new HashMap<>(); + + var mobSettings = getSessionMobSettings(request, response); + + for (var entry : mobSettings.wrapTypes().entrySet()) { + var container = DataDescriptionContainer.of(entry.getValue()); + definitions.put(entry.getKey(), container); + } + + return writeJsonResponse(response, definitions); + } + + public Object removeWrapType(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + + var type = EnumUtil.parse(request.params(":type"), BloodMobType.class); + + if (type == null) halt(HttpStatus.BAD_REQUEST_400, "Unknown BloodMobType"); + + var remove = mobSettings.wrapTypes().remove(type) != null; + return respondStatus(response, remove ? HttpStatus.ACCEPTED_202 : HttpStatus.NOT_MODIFIED_304); + } + + public Object addWrapType(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + var params = request.params(":type"); + var type = EnumUtil.parse(params, BloodMobType.class); + + if (type == null) halt(HttpStatus.BAD_REQUEST_400, "Unknown BloodMobType"); + + var typeSetting = readInput(request, type.typeSettingClazz()); + + mobSettings.wrapTypes().put(type, typeSetting); + + return respondCreated(response); + } + + public Object getSetting(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + var params = request.params(":setting"); + + DataDescriptionContainer container; + + switch (params.toLowerCase(Locale.ROOT)) { + case "extension" -> container = DataDescriptionContainer.of(mobSettings.extension()); + case "extension.equipment" -> container = DataDescriptionContainer.of(mobSettings.extension().equipment()); + case "equipment" -> container = DataDescriptionContainer.of(mobSettings.equipment()); + case "drops" -> container = DataDescriptionContainer.of(mobSettings.drops()); + case "behaviour" -> { + var configuration = getSessionMobSettings(request, response); + var nodeMap = configuration.behaviour().behaviourMap(); + var definitions = ClassDefintionUtil.getBehaviourDefinitions(configuration.behaviour()); + container = DataDescriptionContainer.of(nodeMap, definitions); + } + default -> { + halt(HttpStatus.BAD_REQUEST_400); + return null; + } + } + + return writeJsonResponse(response, container); + } + + public Object setSetting(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + var params = request.params(":setting"); + + var body = request.body(); + + switch (params.toLowerCase(Locale.ROOT)) { + case "extension" -> mobSettings.extension(readInput(request, Extension.class)); + case "extension.equipment" -> mobSettings.extension().equipment(readInput(request, Equipment.class)); + case "equipment" -> mobSettings.equipment(readInput(request, Equipment.class)); + case "drops" -> mobSettings.drops(readInput(request, Drops.class)); + default -> { + halt(HttpStatus.BAD_REQUEST_400, "Unkown setting"); + return null; + } + } + + return respondCreated(response); + } + + public Object addNode(Request request, Response response) { + var nodes = getNodes(request, response); + + var node = readInput(request, Node.class); + + var chain = nodes.second.get(nodes.first); + if (!(chain.getLast() instanceof NodeHolder)) { + halt(HttpStatus.NOT_MODIFIED_304, "Chain is closed"); + } + + chain.addNode(node); + return respondCreated(response); + } + + public Object createNode(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + var type = request.params(":type"); + var nodeType = EnumUtil.parse(type, BehaviourNodeType.class); + if (nodeType == null) { + halt(HttpStatus.BAD_REQUEST_400, "Unknown node type"); + return null; + } + + var node = readInput(request, Node.class); + return respondStatus(response, HttpStatus.CREATED_201, String.valueOf(mobSettings.behaviour().addNode(nodeType, node))); + } + + public Object removeLastNode(Request request, Response response) { + var nodes = getNodes(request, response); + var node = nodes.second.get(nodes.first); + + if (node.isLast()) { + halt(HttpStatus.NOT_MODIFIED_304, "The last node cant be removed. Use delete instead."); + } + + node.removeLast(); + + return respondAccepted(response); + } + + public Object deleteNode(Request request, Response response) { + var nodes = getNodes(request, response); + + nodes.second.remove(nodes.first); + + return respondAccepted(response); + } + + public Object nextNodes(Request request, Response response) { + var nodes = getNodes(request, response); + var node = nodes.second.get(nodes.first); + var availableNodes = NodeRegistry.getAvailableNodes(node, ContextContainerFactory.mock(nodes.third)); + var definitions = availableNodes.stream().map(ClassDefinition::of).collect(Collectors.toList()); + return writeJsonResponse(response, definitions); + } + + public Object getItems(Request request, Response response) { + var session = getSession(request, response); + var simpleItems = session.readData(data -> data.settingsContainer().items()); + return writeJsonResponse(response, simpleItems); + } + + public Object deleteItem(Request request, Response response) { + var session = getSession(request, response); + var params = request.params(":id"); + int id; + try { + id = Integer.parseInt(params); + } catch (NumberFormatException e) { + halt(HttpStatus.BAD_REQUEST_400); + return null; + } + var removed = session.readData(mobEditorPayload -> mobEditorPayload.settingsContainer().items() + .removeIf(item -> item.id() == id)); + return respondStatus(response, removed ? HttpStatus.OK_200 : HttpStatus.NOT_MODIFIED_304); + } + + private MobConfiguration getSessionMobSettings(Request request, Response response) { + var session = getSession(request, response); + var identifier = request.params(":identifier"); + var mobConfiguration = session.readData(data -> data.settingsContainer().getMobConfig(identifier)); + if (mobConfiguration.isEmpty()) halt(HttpStatus.BAD_REQUEST_400, "Mob does not exist."); + return mobConfiguration.get(); + } + + @NotNull + private Triple, BehaviourNodeType> getNodes(Request request, Response response) { + var mobSettings = getSessionMobSettings(request, response); + var type = request.params(":type"); + var idParam = request.params(":id"); + + var id = 0; + try { + id = Integer.parseInt(idParam); + } catch (NumberFormatException e) { + halt(HttpStatus.BAD_REQUEST_400, "Invalid id"); + } + + var nodeType = EnumUtil.parse(type, BehaviourNodeType.class); + if (nodeType == null) halt(HttpStatus.BAD_REQUEST_400, "Unknown node type"); + + var nodes = mobSettings.behaviour().getNodes(nodeType); + if (id >= nodes.size() || id < 0) { + halt(HttpStatus.BAD_REQUEST_400, "Invalid id"); + } + return Triple.of(id, nodes, nodeType); + } + + public Object nextTypeNodes(Request request, Response response) { + var type = request.params(":type"); + var nodeType = EnumUtil.parse(type, BehaviourNodeType.class); + if (nodeType == null) halt(HttpStatus.BAD_REQUEST_400, "Unknown node type"); + + var availableNodes = NodeRegistry.getAvailableNodes(nodeType); + + var definitions = availableNodes.stream().map(ClassDefinition::of).collect(Collectors.toList()); + return writeJsonResponse(response, definitions); + } + + public Object getEventTypes(Request request, Response response) { + var collect = Arrays.stream(BehaviourNodeType.values()).map(Enum::name).collect(Collectors.toList()); + return writeJsonResponse(response, collect, HttpStatus.OK_200); + } + + public Object getChain(Request request, Response response) { + var nodes = getNodes(request, response); + var chain = nodes.second.get(nodes.first); + var collect = chain.getClasses(new HashSet<>()).stream().map(ClassDefinition::of).collect(Collectors.toSet()); + var container = new NodeChain(chain, collect); + return writeJsonResponse(response, container); + } + + public Object getNodeType(Request request, Response response) { + var type = request.params(":type"); + List> collect = Collections.emptyList(); + switch (type.toLowerCase(Locale.ROOT)) { + case "node" -> collect = NodeRegistry.nodes(); + case "predicate" -> collect = NodeRegistry.predicates(); + default -> halt(HttpStatus.BAD_REQUEST_400, "Invalid node type"); + } + + return writeJsonResponse(response, ClassDefinition.of(collect)); + } + + public Object getNodeTypes(Request request, Response response) { + Map> definitions = new HashMap<>(); + definitions.put(ValueType.NODE.name(), ClassDefinition.of(NodeRegistry.nodes())); + definitions.put(ValueType.PREDICATE.name(), ClassDefinition.of(NodeRegistry.predicates())); + + return writeJsonResponse(response, definitions); + } + + private Object writeJsonResponse(Response response, Object object) { + return writeJsonResponse(response, object, HttpStatus.OK_200); + } + + private Object respondStatus(Response response, int status) { + return respondStatus(response, status, null); + } + + private Object respondStatus(Response response, int status, String message) { + response.status(status); + response.type(MediaType.PLAIN_TEXT_UTF_8.type()); + return message == null ? response.status() : message; + } + + private T readInput(Request request, Class clazz) { + try { + return MobMapper.mapper().readValue(request.body(), clazz); + } catch (JsonProcessingException e) { + halt(HttpStatus.BAD_REQUEST_400, "Invalid format."); + } + return null; + } + + private Object respondCreated(Response response) { + return respondStatus(response, HttpStatus.CREATED_201); + } + + private Object respondAccepted(Response response) { + return respondStatus(response, HttpStatus.ACCEPTED_202); + } + + private Object writeJsonResponse(Response response, Object object, int code) { + try { + response.body(MobMapper.mapper().writeValueAsString(object)); + } catch (JsonProcessingException e) { + log.error("Could not serialize", e); + halt(HttpStatus.INTERNAL_SERVER_ERROR_500); + } + + response.type(MediaType.JSON_UTF_8.type()); + response.status(code); + return response.body(); + } + + public Object removeGlobalDrop(Request request, Response response) { + var session = getSession(request, response); + var drop = readInput(request, Drop.class); + var removed = session.sessionData().settingsContainer().globalDrops().remove(drop); + return respondStatus(response, removed ? HttpStatus.ACCEPTED_202 : HttpStatus.NOT_MODIFIED_304); + } + + public Object getGlobalDrops(Request request, Response response) { + var session = getSession(request, response); + return writeJsonResponse(response, session.sessionData().settingsContainer().globalDrops()); + } + + private static class NodeChain { + Node data; + Set definitions; + + public NodeChain(Node data, Set definitions) { + this.data = data; + this.definitions = definitions; + } + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/SessionHolder.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/SessionHolder.java new file mode 100644 index 00000000..bb56a540 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/modules/MobEditor/SessionHolder.java @@ -0,0 +1,32 @@ +package de.eldoria.bloodnight.webservice.modules.mobeditor; + +import de.eldoria.bloodnight.webservice.SessionService; +import de.eldoria.bloodnight.webservice.sessions.Session; +import spark.Request; +import spark.Response; + +public class SessionHolder { + private final SessionService sessionService = SessionService.create(); + + protected Session getSession(Request request, Response response) { + var token = request.headers("token"); + return sessionService.getSession(token); + } + + public Session openSession(T data) { + return sessionService.openSession(data); + } + + public Session getClosedSession(Request request, Response response) { + var token = request.headers("token"); + return sessionService.getClosedSession(token); + } + + public Session closeSession(Session session) { + return sessionService.closeSession(session); + } + + public SessionService sessionService() { + return sessionService; + } +} diff --git a/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/sessions/Session.java b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/sessions/Session.java new file mode 100644 index 00000000..56815f93 --- /dev/null +++ b/BloodNight-web/src/main/java/de/eldoria/bloodnight/webservice/sessions/Session.java @@ -0,0 +1,78 @@ +package de.eldoria.bloodnight.webservice.sessions; + +import com.google.common.hash.Hashing; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.function.Consumer; +import java.util.function.Function; + +public class Session { + private static long incr = 0; + private final String accessToken; + private String retrievalToken; + Instant started = Instant.now(); + Instant lastActive = Instant.now(); + boolean closed = false; + T sessionData; + + public Session(T sessionData) { + this.accessToken = createToken(); + this.sessionData = sessionData; + } + + /** + * Closes + */ + public void close() { + if(closed) throw new IllegalStateException(); + closed = true; + retrievalToken = createToken(); + } + + public void alterData(Consumer apply) { + lastActive = Instant.now(); + apply.accept(sessionData); + } + + public R readData(Function apply) { + lastActive = Instant.now(); + return apply.apply(sessionData); + } + + public Instant started() { + return started; + } + + public Instant lastActive() { + return lastActive; + } + + public boolean isClosed() { + return closed; + } + + public String accessToken() { + return accessToken; + } + + public String retrievaltoken() { + lastActive = Instant.now(); + return retrievalToken; + } + + public T sessionData() { + lastActive = Instant.now(); + return sessionData; + } + + private String createToken() { + return Hashing.sha256() + .hashString(System.currentTimeMillis() + "." + System.nanoTime() + "." + getId(), StandardCharsets.UTF_8) + .toString(); + } + + private static synchronized long getId() { + return incr++; + } +} diff --git a/BloodNight-web/src/main/resources/log4j2.xml b/BloodNight-web/src/main/resources/log4j2.xml new file mode 100644 index 00000000..e62ccabc --- /dev/null +++ b/BloodNight-web/src/main/resources/log4j2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/MobCheck.java b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/MobCheck.java new file mode 100644 index 00000000..f61926d8 --- /dev/null +++ b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/MobCheck.java @@ -0,0 +1,28 @@ +package de.eldoria.bloodnight.serializing; + +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Slime; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public class MobCheck { + @Test + public void findMobs() { + var collect = Arrays.stream(EntityType.values()) + .filter(e -> e.getEntityClass() != null) + .filter(e -> Mob.class.isAssignableFrom(e.getEntityClass())) + .map(e -> e.name() + "(EntityType."+ e.name() +", TypeSetting.class)") + .sorted() + .collect(Collectors.joining(",\n")); + System.out.println(collect); + } + + @Test + public void testMob() { + Assertions.assertTrue(Mob.class.isAssignableFrom(Slime.class)); + } +} diff --git a/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeLayout.java b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeLayout.java new file mode 100644 index 00000000..e3d1ed16 --- /dev/null +++ b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeLayout.java @@ -0,0 +1,25 @@ +package de.eldoria.bloodnight.serializing; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion; +import de.eldoria.bloodnight.serialization.ClassDefinition; +import org.junit.jupiter.api.Test; + +public class NodeLayout { + + @Test + public void test() throws JsonProcessingException { + var of = ClassDefinition.of(OtherPotion.class); + + var mapper = new ObjectMapper() + .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) + .setDefaultPrettyPrinter(new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter())); + var s = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(of); + System.out.println(s); + } +} diff --git a/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeSerializerTest.java b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeSerializerTest.java new file mode 100644 index 00000000..5bad0eb2 --- /dev/null +++ b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/NodeSerializerTest.java @@ -0,0 +1,29 @@ +package de.eldoria.bloodnight.serializing; + +import com.fasterxml.jackson.core.JsonProcessingException; +import de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion; +import de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter; +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.serialization.mapper.MobMapper; +import de.eldoria.bloodnight.serialization.NodeData; +import org.bukkit.potion.PotionEffectType; +import org.junit.jupiter.api.Test; + +public class NodeSerializerTest { + @Test + public void test() throws JsonProcessingException { + var otherPotion = new OtherPotion(PotionEffectType.BLINDNESS, 20, 2, true); + var cooldownFilter = new CooldownFilter(10, otherPotion); + var predicateFilter = new PredicateFilter(cooldownFilter, false, new HasTarget()); + var moveToLocation = new MoveToLocation(predicateFilter, MoveToLocation.LocationSource.OLD); + + var data = NodeData.of(moveToLocation); + var serialize = MobMapper.mapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(data); + + System.out.println(serialize); + } +} diff --git a/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/SettingsContainerTest.java b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/SettingsContainerTest.java new file mode 100644 index 00000000..0cd19159 --- /dev/null +++ b/BloodNight-web/src/test/java/de/eldoria/bloodnight/serializing/SettingsContainerTest.java @@ -0,0 +1,100 @@ +package de.eldoria.bloodnight.serializing; + +import be.seeseemelk.mockbukkit.MockBukkit; +import com.fasterxml.jackson.core.JsonProcessingException; +import de.eldoria.bloodnight.bloodmob.drop.Drop; +import de.eldoria.bloodnight.bloodmob.nodeimpl.action.OtherPotion; +import de.eldoria.bloodnight.bloodmob.nodeimpl.filter.CooldownFilter; +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.registry.MobRegistry; +import de.eldoria.bloodnight.bloodmob.registry.items.ItemRegistry; +import de.eldoria.bloodnight.bloodmob.serialization.container.MobEditorPayload; +import de.eldoria.bloodnight.bloodmob.serialization.container.SettingsContainer; +import de.eldoria.bloodnight.bloodmob.serialization.mapper.MobMapper; +import de.eldoria.bloodnight.bloodmob.settings.BehaviourNodeType; +import de.eldoria.bloodnight.bloodmob.settings.MobConfiguration; +import de.eldoria.bloodnight.serialization.DataDescriptionContainer; +import de.eldoria.bloodnight.util.ClassDefintionUtil; +import de.eldoria.eldoutilities.items.ItemStackBuilder; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.potion.PotionEffectType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +class SettingsContainerTest { + + private static MobRegistry mobRegistry; + public static MobConfiguration testMob; + private static ItemRegistry itemRegistry; + + @BeforeAll + public static void setup() { + MockBukkit.mock(); + + mobRegistry = new MobRegistry(); + testMob = new MobConfiguration("test_mob"); + mobRegistry.register(testMob); + var otherPotion = new OtherPotion(PotionEffectType.BLINDNESS, 20, 2, true); + var cooldownFilter = new CooldownFilter(10, otherPotion); + var predicateFilter = new PredicateFilter(cooldownFilter, false, new HasTarget()); + var moveToLocation = new MoveToLocation(predicateFilter, MoveToLocation.LocationSource.OLD); + + testMob.behaviour().addNode(BehaviourNodeType.TICK, moveToLocation); + testMob.behaviour().addNode(BehaviourNodeType.ON_KILL, moveToLocation); + testMob.behaviour().addNode(BehaviourNodeType.ON_DAMAGE_BY_ENTITY, moveToLocation); + + itemRegistry = new ItemRegistry(); + itemRegistry.register(ItemStackBuilder.of(Material.DIAMOND_BOOTS) + .withEnchant(Enchantment.DURABILITY, 3, true) + .build()); + itemRegistry.register(ItemStackBuilder.of(Material.DIAMOND_CHESTPLATE) + .withLore("This is", "a nice", "Lore") + .build()); + } + + @Test + public void settingContainerSerialization() throws JsonProcessingException { + var drops = new ArrayList(); + drops.add(new Drop(0, 5, 10)); + drops.add(new Drop(0, 2, 10)); + drops.add(new Drop(2, 12, 80)); + + var initContainer = SettingsContainer.from(itemRegistry, mobRegistry, drops); + var mobEditorPayload = new MobEditorPayload(initContainer); + var serializedContainer = MobMapper.mapper().writerWithDefaultPrettyPrinter().writeValueAsString(initContainer); + System.out.println(serializedContainer); + + var settingsContainer = MobMapper.mapper().readValue(serializedContainer, SettingsContainer.class); + Assertions.assertEquals(initContainer.hashCode(), settingsContainer.hashCode()); + + var of = DataDescriptionContainer.of(testMob); + var s = MobMapper.mapper().writeValueAsString(of); + System.out.println(s); + + var serMobEditorPayload = MobMapper.mapper().writeValueAsString(mobEditorPayload); + System.out.println(serMobEditorPayload); + } + + @Test + public void behaviourSerialization() throws JsonProcessingException { + var nodeMap = testMob.behaviour().behaviourMap(); + + var definitions = ClassDefintionUtil.getBehaviourDefinitions(testMob.behaviour()); + + var container = DataDescriptionContainer.of(nodeMap, definitions); + var s = MobMapper.mapper().writeValueAsString(container); + System.out.println(s); + } + + @Test + public void itemSerialization() throws JsonProcessingException { + var s = MobMapper.mapper().writeValueAsString(itemRegistry.getAsSimpleItems()); + System.out.println(s); + } +} \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index 29ebfa54..1139200d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,203 +1,150 @@ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - The precise terms and conditions for copying, distribution and -modification follow. +The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically +designed to ensure cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the +works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions +of a program--to make sure it remains free software for all its users. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make +sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive +source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and +that you know you can do these things. + +Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the +software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the +software. + +A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if +they receive widespread use, become available for other developers to incorporate. Many developers of free software are +heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this +result may fail to come about. The GNU General Public License permits making a modified version and letting the public +access it on a server without ever releasing its source code to the public. + +The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code +becomes available to the community. It requires the operator of a network server to provide the source code of the +modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly +accessible server, gives the public access to the source code of the modified version. + +An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar +goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero +GPL which permits relicensing under this license. + +The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS - 0. Definitions. +0. Definitions. - "This License" refers to version 3 of the GNU Affero General Public License. +"This License" refers to version 3 of the GNU Affero General Public License. - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". " +Licensees" and "recipients" may be individuals or organizations. - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, +other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a +work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the Program. + +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily +liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. +Propagation includes copying, distribution (with or without modification), making available to the public, and in some +countries other activities as well. + +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction +with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright +notice, and (2) +tells the user that there is no warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a +list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. + +The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means +any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, +or, in the case of interfaces specified for a particular programming language, one that is widely used among developers +working in that language. + +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in +the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to +enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is +available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: +(if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used +to run it. + +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and ( +for an executable work) run the object code and to modify the work, including scripts to control those activities. +However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs +which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding +Source includes interface definition files associated with source files for the work, and the source code for shared +libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data +communication or control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the +Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. + +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided +the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. +The output from running a covered work is covered by this License only if the output, given its content, constitutes a +covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license +otherwise remains in force. You may convey covered works to others for the sole purpose of having them make +modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do not control copyright. Those thus making or running +the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that +prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not +allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling +obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or +restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the +extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you +disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, +your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating +that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices +of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for +a fee. + +5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source +code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. @@ -220,22 +167,17 @@ terms of section 4, provided that you also meet all of these conditions: interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of +the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or +distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the +compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause +this License to apply to the other parts of the aggregate. - 6. Conveying Non-Source Forms. +6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the @@ -278,77 +220,55 @@ in one of these ways: Source of the work are being offered to the general public at no charge under subsection 6d. - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, +need not be included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used +for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In +determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a +particular product received by a particular user, "normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way in which the particular user actually uses, or +expects or is expected to use, the product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of +the product. + +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information +required to install and execute modified versions of a covered work in that User Product from a modified version of its +Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code +is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the +conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to +the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding +Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not +apply if neither you nor any third party retains the ability to install modified object code on the User Product (for +example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support +service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product +in which it has been modified or installed. Access to a network may be denied when the modification itself materially +and adversely affects the operation of the network or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format +that is publicly documented (and with an implementation available to the public in source code form), and must require +no special password or key for unpacking, reading or copying. + +7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of +its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were +included in this License, to the extent that they are valid under applicable law. If additional permissions apply only +to part of the Program, that part may be used separately under those permissions, but the entire Program remains +governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or +from any part of it. (Additional permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have +or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by +the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or @@ -373,261 +293,188 @@ that material) supplement the terms of this License with terms: any liability that these contractual assumptions directly impose on those licensors and authors. - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a +All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the +Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with +a term that is a further restriction, you may remove that term. If a license document contains a further restriction but +permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a +statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as +exceptions; the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to +propagate or modify it is void, and will automatically terminate your rights under this License (including any patent +licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is +reinstated (a) +provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) +permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days +after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you +of the violation by some reasonable means, this is the first time you have received notice of violation of this +License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the +notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or +rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not +qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a +covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not +require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered +work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, +modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third +parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or +subdividing an organization, or merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work +the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with +reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For +example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, +and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, +selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the +Program is based. The work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already +acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed only as a consequence of further +modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential +patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its +contributor version. + +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not +to enforce a patent +(such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a +patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not +available for anyone to copy, free of charge and under the terms of this License, through a publicly available network +server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, +or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a +manner consistent with the requirements of this License, to extend the patent license to downstream recipients. " +Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in +a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in +that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring +conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing +them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is +automatically extended to all recipients of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, +or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You +may not convey a covered work if you are a party to an arrangement with a third party that is in the business of +distributing software, under which you make payment to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a +discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from +those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered +work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to +infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to +satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence +you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further +conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License +would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently +offer all users interacting with it remotely through a computer network (if your version supports such interaction) an +opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a +network server at no charge, through some standard or customary means of facilitating copying of software. This +Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public +License that is incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work +licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting +work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it +is combined will remain governed by version 3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time +to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the +GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever +published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be +used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the +Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed +on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING +THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR +IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO +MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO +LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to +their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil +liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program +in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve +this is to make it free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to +most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer +to where the full notice is found. Copyright (C) @@ -647,15 +494,11 @@ the "copyright" line and a pointer to where the full notice is found. Also add information on how to contact you by electronic and paper mail. - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see +If your software can interact with users remotely through a computer network, you should also make sure that it provides +a way for users to get its source. For example, if your program is a web application, its interface could display a " +Source" link that leads users to an archive of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for +the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..cd0504a5 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + // Support convention plugins written in Kotlin. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build. + `kotlin-dsl` +} + +repositories { + // Use the plugin portal to apply community plugins in convention plugins. + gradlePluginPortal() +} diff --git a/buildSrc/src/main/kotlin/PublishData.kt b/buildSrc/src/main/kotlin/PublishData.kt new file mode 100644 index 00000000..7177d5b0 --- /dev/null +++ b/buildSrc/src/main/kotlin/PublishData.kt @@ -0,0 +1,36 @@ +import org.gradle.api.Project + +class PublishData(private val project: Project) { + var type: Type = getReleaseType() + var hashLength: Int = 7 + + private fun getReleaseType(): Type { + val branch = getCheckedOutBranch() + return when { + branch.contentEquals("master") -> Type.RELEASE + branch.startsWith("dev") -> Type.DEV + else -> Type.SNAPSHOT + } + } + + private fun getCheckedOutGitCommitHash(): String = System.getenv("GITHUB_SHA")?.substring(0, hashLength) ?: "local" + + private fun getCheckedOutBranch(): String = System.getenv("GITHUB_REF")?.replace("refs/heads/", "") ?: "local" + + fun getVersion(): String = getVersion(false) + + fun getVersion(appendCommit: Boolean): String = + type.append(getVersionString(), appendCommit, getCheckedOutGitCommitHash()) + + private fun getVersionString(): String = (project.version as String).replace("-SNAPSHOT", "").replace("-DEV", "") + + fun getRepository(): String = type.repo + + enum class Type(private val append: String, val repo: String, private val addCommit: Boolean) { + RELEASE("", "https://eldonexus.de/repository/maven-releases/", false), + DEV("-DEV", "https://eldonexus.de/repository/maven-dev/", true), + SNAPSHOT("-SNAPSHOT", "https://eldonexus.de/repository/maven-snapshots/", true); + + fun append(name: String, appendCommit: Boolean, commitHash:String): String = name.plus(append).plus(if (appendCommit && addCommit) "-".plus(commitHash) else "") + } +} diff --git a/buildSrc/src/main/kotlin/de.eldoria.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/de.eldoria.java-conventions.gradle.kts new file mode 100644 index 00000000..d950f8db --- /dev/null +++ b/buildSrc/src/main/kotlin/de.eldoria.java-conventions.gradle.kts @@ -0,0 +1,55 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "de.eldoria" +version = "1.0.0-SNAPSHOT" +java.sourceCompatibility = JavaVersion.VERSION_1_8 +val lombokVersion = "1.18.20" + +repositories { + maven { url = uri("https://eldonexus.de/repository/maven-public/") } + maven { url = uri("https://eldonexus.de/repository/maven-proxies/") } + maven { url = uri("https://repo.maven.apache.org/maven2/") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") } + maven { url = uri("https://mvn.lumine.io/repository/maven-public/") } + maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") } + maven { url = uri("https://mvn.intellectualsites.com/content/repositories/snapshots") } +} + +dependencies { + implementation("de.eldoria:eldo-util:1.8.8-DEV") + compileOnly("org.spigotmc", "spigot-api", "1.16.5-R0.1-SNAPSHOT") + compileOnly("org.projectlombok", "lombok", lombokVersion) + annotationProcessor("org.projectlombok", "lombok", lombokVersion) + compileOnly("org.jetbrains", "annotations", "16.0.2") + + testImplementation(platform("org.junit:junit-bom:5.7.2")) + testImplementation("org.junit.jupiter:junit-jupiter") + testImplementation("org.spigotmc", "spigot-api", "1.16.5-R0.1-SNAPSHOT") + testImplementation("com.github.seeseemelk", "MockBukkit-v1.16", "1.0.0") +} + +allprojects { + java { + withSourcesJar() + withJavadocJar() + } +} + +tasks { + publish { + dependsOn(build) + } + + compileJava { + options.encoding = "UTF-8" + } + test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/de.eldoria.library-conventions.gradle.kts b/buildSrc/src/main/kotlin/de.eldoria.library-conventions.gradle.kts new file mode 100644 index 00000000..5c9cebb6 --- /dev/null +++ b/buildSrc/src/main/kotlin/de.eldoria.library-conventions.gradle.kts @@ -0,0 +1,51 @@ +plugins { + `java-library` + `maven-publish` + id("de.eldoria.java-conventions") +} + +publishing { + publications { + val publishData = PublishData(project) + + create("maven") { + from(components["java"]) + groupId = project.group as String? + artifactId = project.name.toLowerCase() + version = publishData.getVersion() + pom { + url.set("https://github.com/eldoriarpg/BloodNight") + developers { + developer { + name.set("Florian Fülling") + organization.set("EldoriaRPG") + organizationUrl.set("https://github.com/eldoriarpg") + } + } + licenses { + license { + name.set("GNU Affero General Public License v3.0") + url.set("https://github.com/eldoriarpg/BloodNight/blob/master/LICENSE.md") + } + } + } + println(configurations.getByName("api").allDependencies) + } + + } + + repositories { + maven { + val publishData = PublishData(project) + name = "EldoNexus" + url = uri(publishData.getRepository()) + + authentication { + credentials(PasswordCredentials::class) { + username = System.getenv("NEXUS_USERNAME") + password = System.getenv("NEXUS_PASSWORD") + } + } + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..05679dc3 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..4f906e0c --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..ac1b06f9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 67797232..00000000 --- a/pom.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - 4.0.0 - - de.eldoria - BloodNight - BloodNight - pom - ${revision} - - - BloodNight-core - BloodNight-api - - - - - jitpack.io - https://jitpack.io - - - - - 0.10.3 - UTF-8 - yyyy-MM-dd HH:mm:ss - 8 - de.eldoria.bloodnight - 3.2.0 - 3.2.1 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - - org.apache.maven.plugins - maven-source-plugin - ${source.version} - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${javadoc.version} - - ${java.version} - - - - attach-javadocs - - jar - - - - - - - - src/main/resources - true - - - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - - - - org.spigotmc - spigot-api - 1.16.5-R0.1-SNAPSHOT - provided - - - - - org.projectlombok - lombok - 1.18.12 - provided - - - org.jetbrains - annotations - 16.0.2 - provided - - - \ No newline at end of file diff --git a/readme.md b/readme.md index e76c6c74..a417fb64 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,9 @@ -[![](https://jitci.com/gh/eldoriarpg/BloodNight/svg)](https://jitci.com/gh/eldoriarpg/BloodNight) +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/eldoriarpg/BloodNight/Verify%20state?style=for-the-badge&label=Building) +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/eldoriarpg/BloodNight/Publish%20to%20Nexus?style=for-the-badge&label=Publishing) +![Sonatype Nexus (Releases)](https://img.shields.io/nexus/maven-releases/de.eldoria/bloodnight-core?label=Release&logo=Release&server=https%3A%2F%2Feldonexus.de&style=for-the-badge) +![Sonatype Nexus (Development)](https://img.shields.io/nexus/maven-dev/de.eldoria/bloodnight-core?label=DEV&logo=Release&server=https%3A%2F%2Feldonexus.de&style=for-the-badge) +![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/de.eldoria/bloodnight-core?color=orange&label=Snapshot&server=https%3A%2F%2Feldonexus.de&style=for-the-badge) + # Blood Night A Minecraft plugin which makes some nights an absolute nightmare. Let's make nights a challenge again. @@ -10,19 +15,29 @@ A Minecraft plugin which makes some nights an absolute nightmare. Let's make nig ## Blood Night as Dependency **Latest Version:**\ -[![](https://jitpack.io/v/de.eldoria/BloodNight.svg)](https://jitpack.io/#de.eldoria/BloodNight) +If you want to use blood night as a dependency you can use these.\ +Make sure to replace the version with the release version from above. +### Gradle +``` kotlin +repositories { + maven { url = uri("https://eldonexus.de/repository/maven-public") } +} -```xml - - jitpack.io - https://jitpack.io - +dependencies { + implementation("de.eldoria", "bloodnight-core", "{version}") +} ``` -```xml - - de.eldoria - BloodNight - {version} - +### Maven +``` xml + + EldoNexus + https://eldonexus.de/repository/maven-public/ + + + + de.eldoria + bloodnight-core + {version} + ``` \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..17b618d9 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,5 @@ +rootProject.name = "BloodNight" +include(":BloodNight-api") +include(":BloodNight-core") +include(":BloodNight-mobs") +include(":BloodNight-web")