Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17ee1ac2ff | ||
|
|
a6fa446d95 | ||
|
|
2f98c0ace5 | ||
|
|
60d7abcda8 | ||
|
|
69a5fa81b4 | ||
|
|
0316e627e1 | ||
|
|
5bc5b47bf8 | ||
|
|
a9c906843d | ||
|
|
85861971d3 | ||
|
|
bdb24e5a14 | ||
|
|
cb481d4532 | ||
|
|
97fba3e243 | ||
|
|
e47c6387a2 | ||
|
|
00df39097c | ||
|
|
efcb406e9a | ||
|
|
9e92ea6062 | ||
|
|
9dbc25df6f | ||
|
|
bc85c5232e | ||
|
|
2f4783f13e | ||
|
|
614241a058 | ||
|
|
c541adb557 | ||
|
|
a484eecc8f | ||
|
|
3933e38891 | ||
|
|
1d5345b367 | ||
|
|
f8513ff1e9 | ||
|
|
ca9c940b2b | ||
|
|
af198d30f7 | ||
|
|
637b239c66 | ||
|
|
124c059294 | ||
|
|
f1d0bd901d | ||
|
|
20f4bf4e78 | ||
|
|
595bc76294 | ||
|
|
9a66e78dcd | ||
|
|
0fcf229bfb | ||
|
|
d2ffc43b17 | ||
|
|
c50f69b372 | ||
|
|
f5eafafc4c | ||
|
|
39372c9b1a | ||
|
|
4c64f03aa1 | ||
|
|
6bb4e301bc | ||
|
|
827e9fd98a | ||
|
|
c3e9bbbc50 | ||
|
|
7328881977 | ||
|
|
00531d0a04 | ||
|
|
5d4a2b4633 | ||
|
|
28c86460fc | ||
|
|
4a1d714b71 | ||
|
|
4ef16530d3 | ||
|
|
a22ad1b22d | ||
|
|
623c3589a3 | ||
|
|
44924cdf83 | ||
|
|
75363181e4 | ||
|
|
1fc9d66457 | ||
|
|
2fdbe0da28 | ||
|
|
a1922cb195 | ||
|
|
725e950092 | ||
|
|
bf123d3105 | ||
|
|
83b6721484 | ||
|
|
dca952c10a | ||
|
|
b2e5896885 | ||
|
|
38542dad5e | ||
|
|
852a9c5fb1 | ||
|
|
12aa0e349e | ||
|
|
351f5d8c16 | ||
|
|
7e4b3075ed | ||
|
|
cf0d725189 | ||
|
|
a9f33fb846 | ||
|
|
4a9ab7a0eb | ||
|
|
3982ab99a6 | ||
|
|
1fb39e55d2 | ||
|
|
56d32b532d | ||
|
|
0d0800dfb5 | ||
|
|
f32110687f | ||
|
|
dbf39f3621 | ||
|
|
9a2f0e3df8 | ||
|
|
56fb9b40b9 | ||
|
|
fbc7bb6f07 | ||
|
|
2294c3758d | ||
|
|
c573da6e31 | ||
|
|
6362931e6b | ||
|
|
0be1f45edc | ||
|
|
9700aa7eac | ||
|
|
75eaf58aa2 | ||
|
|
63352989b1 | ||
|
|
dd5e0e3847 | ||
|
|
4f009c6d57 | ||
|
|
09d4db816e | ||
|
|
fb7799e931 | ||
|
|
13a1965f03 | ||
|
|
3abefb73f9 | ||
|
|
a35f5bb405 | ||
|
|
88a7fb53a3 | ||
|
|
866ba8440d | ||
|
|
61896bbddd | ||
|
|
7a4891d4e3 | ||
|
|
dbd5cd341e | ||
|
|
7df707a59d | ||
|
|
92dfa32d07 | ||
|
|
5cad1d31e3 | ||
|
|
e4c0418fd4 | ||
|
|
54c74d0138 | ||
|
|
6e21bdeb5b | ||
|
|
00439a1b04 | ||
|
|
87684abbbb | ||
|
|
0cbf78733e | ||
|
|
ecf0e7c356 | ||
|
|
f20d9884b5 | ||
|
|
61d713ad4d | ||
|
|
ca5cce3f40 | ||
|
|
1c8edac807 | ||
|
|
98b465f8f3 | ||
|
|
3c3e34eda3 | ||
|
|
02ad6f7810 | ||
|
|
5369ee7d42 | ||
|
|
c441e0761f | ||
|
|
a02dd06c20 | ||
|
|
957af5c5bf | ||
|
|
2c51a6900f | ||
|
|
e09e9b4e8d | ||
|
|
02497d485b | ||
|
|
bd32f3bc8d | ||
|
|
7176342e15 | ||
|
|
32ef8d8c5c | ||
|
|
92f8787eb9 | ||
|
|
5403f7a9ed | ||
|
|
2924d6f560 | ||
|
|
36c0708c17 | ||
|
|
b9fe54e883 | ||
|
|
5cc2f23547 | ||
|
|
30514ba780 | ||
|
|
02e6c5e8f3 | ||
|
|
fac97329aa | ||
|
|
cdf5cc3abe | ||
|
|
4cb630d201 | ||
|
|
79d6277d94 | ||
|
|
1a90fa6707 | ||
|
|
d0d64b3e58 | ||
|
|
49273abbfc |
@@ -39,7 +39,7 @@ and many more.
|
|||||||
# For developers
|
# For developers
|
||||||
|
|
||||||
## Javadoc
|
## Javadoc
|
||||||
The 6.13.0 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.13.0/javadoc/)
|
The 6.27.2 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.27.2/javadoc/)
|
||||||
|
|
||||||
## Plugin Information
|
## Plugin Information
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ dependencies {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `Tag` with a release tag for eco, eg `6.13.0`.
|
Replace `Tag` with a release tag for eco, eg `6.27.2`.
|
||||||
|
|
||||||
Maven:
|
Maven:
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ Maven:
|
|||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `Tag` with a release tag for eco, eg `6.13.0`.
|
Replace `Tag` with a release tag for eco, eg `6.27.2`.
|
||||||
|
|
||||||
## Build locally:
|
## Build locally:
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ dependencies {
|
|||||||
implementation(project(":eco-core:core-backend"))
|
implementation(project(":eco-core:core-backend"))
|
||||||
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
|
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
|
||||||
implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
|
implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
|
||||||
|
implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@@ -92,12 +93,12 @@ allprojects {
|
|||||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||||
|
|
||||||
// Adventure
|
// Adventure
|
||||||
compileOnly("net.kyori:adventure-api:4.9.3")
|
compileOnly("net.kyori:adventure-api:4.10.0")
|
||||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
|
compileOnly("net.kyori:adventure-text-serializer-gson:4.10.0")
|
||||||
compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3")
|
compileOnly("net.kyori:adventure-text-serializer-legacy:4.10.0")
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
compileOnly("com.google.guava:guava:31.0.1-jre")
|
compileOnly("com.google.guava:guava:31.1-jre")
|
||||||
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
|
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ allprojects {
|
|||||||
exclude(group = "org.spongepowered", module = "configurate-hocon")
|
exclude(group = "org.spongepowered", module = "configurate-hocon")
|
||||||
exclude(group = "com.darkblade12", module = "particleeffect")
|
exclude(group = "com.darkblade12", module = "particleeffect")
|
||||||
exclude(group = "com.github.cryptomorin", module = "XSeries")
|
exclude(group = "com.github.cryptomorin", module = "XSeries")
|
||||||
|
exclude(group = "net.wesjd", module = "anvilgui")
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.testImplementation {
|
configurations.testImplementation {
|
||||||
@@ -129,8 +131,8 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate("org.bstats", "com.willfp.eco.shaded.bstats")
|
relocate("org.bstats", "com.willfp.eco.libs.bstats")
|
||||||
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")
|
relocate("redempt.crunch", "com.willfp.eco.libs.crunch")
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Adventure
|
// Adventure
|
||||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
|
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
|
||||||
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
|
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||||
@@ -13,6 +12,10 @@ dependencies {
|
|||||||
group 'com.willfp'
|
group 'com.willfp'
|
||||||
version rootProject.version
|
version rootProject.version
|
||||||
|
|
||||||
|
java {
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
build.dependsOn publishToMavenLocal
|
build.dependsOn publishToMavenLocal
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
@@ -33,4 +36,4 @@ publishing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.willfp.eco.core.config.wrapper.ConfigFactory;
|
|||||||
import com.willfp.eco.core.data.ProfileHandler;
|
import com.willfp.eco.core.data.ProfileHandler;
|
||||||
import com.willfp.eco.core.data.keys.KeyRegistry;
|
import com.willfp.eco.core.data.keys.KeyRegistry;
|
||||||
import com.willfp.eco.core.drops.DropQueueFactory;
|
import com.willfp.eco.core.drops.DropQueueFactory;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityController;
|
||||||
import com.willfp.eco.core.events.EventManager;
|
import com.willfp.eco.core.events.EventManager;
|
||||||
import com.willfp.eco.core.extensions.ExtensionLoader;
|
import com.willfp.eco.core.extensions.ExtensionLoader;
|
||||||
import com.willfp.eco.core.factory.MetadataValueFactory;
|
import com.willfp.eco.core.factory.MetadataValueFactory;
|
||||||
@@ -20,6 +21,7 @@ import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -32,7 +34,6 @@ import java.util.logging.Logger;
|
|||||||
* @see Eco#getHandler()
|
* @see Eco#getHandler()
|
||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
@SuppressWarnings("removal")
|
|
||||||
public interface Handler {
|
public interface Handler {
|
||||||
/**
|
/**
|
||||||
* Create a scheduler.
|
* Create a scheduler.
|
||||||
@@ -262,4 +263,23 @@ public interface Handler {
|
|||||||
@NotNull
|
@NotNull
|
||||||
PluginProps getProps(@Nullable PluginProps existing,
|
PluginProps getProps(@Nullable PluginProps existing,
|
||||||
@NotNull Class<? extends EcoPlugin> plugin);
|
@NotNull Class<? extends EcoPlugin> plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a string with MiniMessage.
|
||||||
|
*
|
||||||
|
* @param message The message.
|
||||||
|
* @return The formatted string.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String formatMiniMessage(@NotNull String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create controlled entity from a mob.
|
||||||
|
*
|
||||||
|
* @param mob The mob.
|
||||||
|
* @param <T> The mob type.
|
||||||
|
* @return The controlled entity.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
<T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.willfp.eco.core.config.interfaces;
|
|||||||
|
|
||||||
import com.willfp.eco.core.config.ConfigType;
|
import com.willfp.eco.core.config.ConfigType;
|
||||||
import com.willfp.eco.core.config.TransientConfig;
|
import com.willfp.eco.core.config.TransientConfig;
|
||||||
|
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||||
import com.willfp.eco.util.NumberUtils;
|
import com.willfp.eco.util.NumberUtils;
|
||||||
import com.willfp.eco.util.StringUtils;
|
import com.willfp.eco.util.StringUtils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -9,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ import java.util.Objects;
|
|||||||
* Contains all methods that must exist in yaml and json configurations.
|
* Contains all methods that must exist in yaml and json configurations.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public interface Config extends Cloneable {
|
public interface Config extends Cloneable, PlaceholderInjectable {
|
||||||
/**
|
/**
|
||||||
* Clears cache.
|
* Clears cache.
|
||||||
*/
|
*/
|
||||||
@@ -563,7 +566,7 @@ public interface Config extends Cloneable {
|
|||||||
*/
|
*/
|
||||||
default double getDoubleFromExpression(@NotNull String path,
|
default double getDoubleFromExpression(@NotNull String path,
|
||||||
@Nullable Player player) {
|
@Nullable Player player) {
|
||||||
return NumberUtils.evaluateExpression(this.getString(path), player);
|
return NumberUtils.evaluateExpression(this.getString(path), player, this.getInjectedPlaceholders());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -629,4 +632,19 @@ public interface Config extends Cloneable {
|
|||||||
* @return The clone.
|
* @return The clone.
|
||||||
*/
|
*/
|
||||||
Config clone();
|
Config clone();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void injectPlaceholders(@NotNull Iterable<StaticPlaceholder> placeholders) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<StaticPlaceholder> getInjectedPlaceholders() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void clearInjectedPlaceholders() {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.willfp.eco.core.config.wrapper;
|
|||||||
|
|
||||||
import com.willfp.eco.core.config.ConfigType;
|
import com.willfp.eco.core.config.ConfigType;
|
||||||
import com.willfp.eco.core.config.interfaces.Config;
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||||
import com.willfp.eco.util.StringUtils;
|
import com.willfp.eco.util.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -134,6 +135,26 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
|
|||||||
return handle.getType();
|
return handle.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectPlaceholders(@NotNull final StaticPlaceholder... placeholders) {
|
||||||
|
handle.injectPlaceholders(placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectPlaceholders(@NotNull final Iterable<StaticPlaceholder> placeholders) {
|
||||||
|
handle.injectPlaceholders(placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StaticPlaceholder> getInjectedPlaceholders() {
|
||||||
|
return handle.getInjectedPlaceholders();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearInjectedPlaceholders() {
|
||||||
|
handle.clearInjectedPlaceholders();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the handle.
|
* Get the handle.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base interface for all custom goals.
|
||||||
|
* <p>
|
||||||
|
* Can be used both for entity goals and target goals.
|
||||||
|
*
|
||||||
|
* @param <T> The type of mob that this goal can be applied to.
|
||||||
|
*/
|
||||||
|
public abstract class CustomGoal<T extends Mob> implements EntityGoal<T>, TargetGoal<T> {
|
||||||
|
/**
|
||||||
|
* The flags for the goal.
|
||||||
|
*/
|
||||||
|
private final Set<GoalFlag> flags = EnumSet.noneOf(GoalFlag.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the goal with a mob.
|
||||||
|
* <p>
|
||||||
|
* This will be run before any implementation code, treat this as the constructor.
|
||||||
|
*
|
||||||
|
* @param mob The mob.
|
||||||
|
*/
|
||||||
|
public abstract void initialize(@NotNull T mob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if the goal can be used.
|
||||||
|
* Will start the goal if this returns true.
|
||||||
|
*
|
||||||
|
* @return If the goal can be used.
|
||||||
|
*/
|
||||||
|
public abstract boolean canUse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick the goal.
|
||||||
|
* <p>
|
||||||
|
* Runs ever tick as long as canUse returns true.
|
||||||
|
* <p>
|
||||||
|
* Runs after start().
|
||||||
|
*/
|
||||||
|
public void tick() {
|
||||||
|
// Override when needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the goal.
|
||||||
|
* <p>
|
||||||
|
* Runs once canUse() returns true.
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
// Override when needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the goal.
|
||||||
|
* <p>
|
||||||
|
* Runs once canUse() returns false.
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
// Override when needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if the goal can continue to be used.
|
||||||
|
*
|
||||||
|
* @return If the goal can continue to be used.
|
||||||
|
*/
|
||||||
|
public boolean canContinueToUse() {
|
||||||
|
return this.canUse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if the goal is interruptable.
|
||||||
|
*
|
||||||
|
* @return If interruptable.
|
||||||
|
*/
|
||||||
|
public boolean isInterruptable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the goal flags.
|
||||||
|
*
|
||||||
|
* @return The flags.
|
||||||
|
*/
|
||||||
|
public EnumSet<GoalFlag> getFlags() {
|
||||||
|
return EnumSet.copyOf(this.flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the flags for the goal.
|
||||||
|
*
|
||||||
|
* @param flags The flags.
|
||||||
|
*/
|
||||||
|
public final void setFlags(@NotNull final GoalFlag... flags) {
|
||||||
|
this.setFlags(EnumSet.copyOf(List.of(flags)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the flags for the goal.
|
||||||
|
*
|
||||||
|
* @param flags The flags.
|
||||||
|
*/
|
||||||
|
public void setFlags(@NotNull final EnumSet<GoalFlag> flags) {
|
||||||
|
this.flags.clear();
|
||||||
|
this.flags.addAll(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T addToEntity(@NotNull final T entity,
|
||||||
|
final int priority) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Shorthand syntax is not supported for custom goals by default as they can be both entity and target goals."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.Eco;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity controller allows for adding targets and goals to entities.
|
||||||
|
*
|
||||||
|
* @param <T> The wrapped mob.
|
||||||
|
*/
|
||||||
|
public interface EntityController<T extends Mob> {
|
||||||
|
/**
|
||||||
|
* Add a target goal to the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @param priority The priority.
|
||||||
|
* @param goal The goal.
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> addTargetGoal(int priority,
|
||||||
|
@NotNull TargetGoal<? super T> goal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all target goals from the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> clearTargetGoals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a target goal from the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @param goal The goal.
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> removeTargetGoal(@NotNull TargetGoal<? super T> goal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an entity goal to the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @param priority The priority.
|
||||||
|
* @param goal The goal.
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> addEntityGoal(int priority,
|
||||||
|
@NotNull EntityGoal<? super T> goal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an entity goal from the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @param goal The goal.
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> removeEntityGoal(@NotNull EntityGoal<? super T> goal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all entity goals from the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
EntityController<T> clearEntityGoals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all goals from the entity.
|
||||||
|
* <p>
|
||||||
|
* Mutates the instance.
|
||||||
|
*
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
default EntityController<T> clearAllGoals() {
|
||||||
|
this.clearTargetGoals();
|
||||||
|
return this.clearEntityGoals();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mob back from the controlled entity.
|
||||||
|
* <p>
|
||||||
|
* Not required to apply changes, as the mob instance will be altered.
|
||||||
|
*
|
||||||
|
* @return The mob.
|
||||||
|
*/
|
||||||
|
T getEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an entity controller for an entity in order to modify targets and goals.
|
||||||
|
*
|
||||||
|
* @param entity The entity.
|
||||||
|
* @param <T> The mob type.
|
||||||
|
* @return The entity controller.
|
||||||
|
*/
|
||||||
|
static <T extends Mob> EntityController<T> getFor(@NotNull final T entity) {
|
||||||
|
return Eco.getHandler().createEntityController(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A goal for entity AI.
|
||||||
|
*
|
||||||
|
* @param <T> The type of mob that the goal can be applied to.
|
||||||
|
*/
|
||||||
|
public interface EntityGoal<T extends Mob> extends Goal<T> {
|
||||||
|
@Override
|
||||||
|
default T addToEntity(@NotNull T entity, int priority) {
|
||||||
|
return EntityController.getFor(entity)
|
||||||
|
.addEntityGoal(priority, this)
|
||||||
|
.getEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalAvoidEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalBreakDoors;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalBreatheAir;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalBreed;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalCatLieOnBed;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalCatSitOnBed;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalEatGrass;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalFleeSun;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalFloat;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalFollowBoats;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalFollowMobs;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalIllusionerBlindnessSpell;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalIllusionerMirrorSpell;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalInteract;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalLeapAtTarget;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalLookAtPlayer;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalMeleeAttack;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalMoveBackToVillage;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalMoveThroughVillage;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalMoveTowardsRestriction;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalMoveTowardsTarget;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalOcelotAttack;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalOpenDoors;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalPanic;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRandomLookAround;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRandomStroll;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRandomSwimming;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRangedAttack;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRangedBowAttack;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRangedCrossbowAttack;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalRestrictSun;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalStrollThroughVillage;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalTempt;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalTryFindWater;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalUseItem;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalWaterAvoidingRandomFlying;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalWaterAvoidingRandomStroll;
|
||||||
|
import com.willfp.eco.core.entities.ai.entity.EntityGoalWolfBeg;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to manage entity goals.
|
||||||
|
*/
|
||||||
|
public final class EntityGoals {
|
||||||
|
/**
|
||||||
|
* All registered deserializers.
|
||||||
|
*/
|
||||||
|
private static final Map<NamespacedKey, KeyedDeserializer<? extends EntityGoal<?>>> BY_KEY = HashBiMap.create();
|
||||||
|
|
||||||
|
static {
|
||||||
|
register(EntityGoalAvoidEntity.DESERIALIZER);
|
||||||
|
register(EntityGoalBreakDoors.DESERIALIZER);
|
||||||
|
register(EntityGoalBreatheAir.DESERIALIZER);
|
||||||
|
register(EntityGoalEatGrass.DESERIALIZER);
|
||||||
|
register(EntityGoalFleeSun.DESERIALIZER);
|
||||||
|
register(EntityGoalFloat.DESERIALIZER);
|
||||||
|
register(EntityGoalFollowBoats.DESERIALIZER);
|
||||||
|
register(EntityGoalFollowMobs.DESERIALIZER);
|
||||||
|
register(EntityGoalInteract.DESERIALIZER);
|
||||||
|
register(EntityGoalLeapAtTarget.DESERIALIZER);
|
||||||
|
register(EntityGoalLookAtPlayer.DESERIALIZER);
|
||||||
|
register(EntityGoalMeleeAttack.DESERIALIZER);
|
||||||
|
register(EntityGoalMoveBackToVillage.DESERIALIZER);
|
||||||
|
register(EntityGoalMoveThroughVillage.DESERIALIZER);
|
||||||
|
register(EntityGoalMoveTowardsRestriction.DESERIALIZER);
|
||||||
|
register(EntityGoalMoveTowardsTarget.DESERIALIZER);
|
||||||
|
register(EntityGoalOcelotAttack.DESERIALIZER);
|
||||||
|
register(EntityGoalOpenDoors.DESERIALIZER);
|
||||||
|
register(EntityGoalPanic.DESERIALIZER);
|
||||||
|
register(EntityGoalRandomLookAround.DESERIALIZER);
|
||||||
|
register(EntityGoalRandomStroll.DESERIALIZER);
|
||||||
|
register(EntityGoalRandomSwimming.DESERIALIZER);
|
||||||
|
register(EntityGoalRangedAttack.DESERIALIZER);
|
||||||
|
register(EntityGoalRangedBowAttack.DESERIALIZER);
|
||||||
|
register(EntityGoalRangedCrossbowAttack.DESERIALIZER);
|
||||||
|
register(EntityGoalRestrictSun.DESERIALIZER);
|
||||||
|
register(EntityGoalStrollThroughVillage.DESERIALIZER);
|
||||||
|
register(EntityGoalTempt.DESERIALIZER);
|
||||||
|
register(EntityGoalTryFindWater.DESERIALIZER);
|
||||||
|
register(EntityGoalUseItem.DESERIALIZER);
|
||||||
|
register(EntityGoalWaterAvoidingRandomFlying.DESERIALIZER);
|
||||||
|
register(EntityGoalWaterAvoidingRandomStroll.DESERIALIZER);
|
||||||
|
register(EntityGoalWolfBeg.DESERIALIZER);
|
||||||
|
register(EntityGoalBreed.DESERIALIZER);
|
||||||
|
register(EntityGoalCatSitOnBed.DESERIALIZER);
|
||||||
|
register(EntityGoalCatLieOnBed.DESERIALIZER);
|
||||||
|
register(EntityGoalIllusionerBlindnessSpell.DESERIALIZER);
|
||||||
|
register(EntityGoalIllusionerMirrorSpell.DESERIALIZER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get deserializer by key.
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @return The deserializer, or null if not found.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static KeyedDeserializer<? extends EntityGoal<? extends Mob>> getByKey(@NotNull final NamespacedKey key) {
|
||||||
|
return BY_KEY.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get deserializer by key, with a defined type (to prevent cluttering code with unsafe casts).
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @param clazz The type of target goal.
|
||||||
|
* @param <T> The type of mob the goal can be applied to.
|
||||||
|
* @return The deserializer, or null if not found.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@SuppressWarnings({"unchecked", "unused"})
|
||||||
|
public static <T extends Mob> KeyedDeserializer<EntityGoal<T>> getByKeyOfType(@NotNull final NamespacedKey key,
|
||||||
|
@NotNull final Class<T> clazz) {
|
||||||
|
return (KeyedDeserializer<EntityGoal<T>>) BY_KEY.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply goal to entity given key and config.
|
||||||
|
* <p>
|
||||||
|
* If the key or config are invalid, the goal will not be applied.
|
||||||
|
*
|
||||||
|
* @param entity The entity.
|
||||||
|
* @param key The key.
|
||||||
|
* @param config The config.
|
||||||
|
* @param priority The priority.
|
||||||
|
* @param <T> The entity type.
|
||||||
|
* @return The entity.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Mob> T applyToEntity(@NotNull final T entity,
|
||||||
|
@NotNull final NamespacedKey key,
|
||||||
|
@NotNull final Config config,
|
||||||
|
final int priority) {
|
||||||
|
KeyedDeserializer<EntityGoal<T>> deserializer = getByKeyOfType(key, (Class<T>) entity.getClass());
|
||||||
|
if (deserializer == null) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityGoal<T> goal = deserializer.deserialize(config);
|
||||||
|
|
||||||
|
if (goal == null) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return goal.addToEntity(entity, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a deserializer for an entity goal.
|
||||||
|
*
|
||||||
|
* @param toRegister The entity goal to register.
|
||||||
|
* @param <T> The type of deserializer.
|
||||||
|
* @return The deserializer.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T extends KeyedDeserializer<? extends EntityGoal<?>>> T register(@NotNull final T toRegister) {
|
||||||
|
BY_KEY.put(toRegister.getKey(), toRegister);
|
||||||
|
return toRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityGoals() {
|
||||||
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic goal for entity AI.
|
||||||
|
*
|
||||||
|
* @param <T> The type of mob that the goal can be applied to.
|
||||||
|
*/
|
||||||
|
public interface Goal<T extends Mob> {
|
||||||
|
/**
|
||||||
|
* Add the entity goal to an entity.
|
||||||
|
* <p>
|
||||||
|
* The lower the priority, the higher up the execution order; so
|
||||||
|
* priority 0 will execute first. Lower priority (higher number) goals
|
||||||
|
* will only execute if all higher priority goals are stopped.
|
||||||
|
*
|
||||||
|
* @param entity The entity.
|
||||||
|
* @param priority The priority.
|
||||||
|
* @return The entity, modified.
|
||||||
|
*/
|
||||||
|
T addToEntity(@NotNull T entity, int priority);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags for ai goals.
|
||||||
|
*/
|
||||||
|
public enum GoalFlag {
|
||||||
|
/**
|
||||||
|
* Move.
|
||||||
|
*/
|
||||||
|
MOVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look around.
|
||||||
|
*/
|
||||||
|
LOOK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jump.
|
||||||
|
*/
|
||||||
|
JUMP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target.
|
||||||
|
*/
|
||||||
|
TARGET
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A goal for entity target AI.
|
||||||
|
*
|
||||||
|
* @param <T> The type of mob that the goal can be applied to.
|
||||||
|
*/
|
||||||
|
public interface TargetGoal<T extends Mob> extends Goal<T> {
|
||||||
|
@Override
|
||||||
|
default T addToEntity(@NotNull T entity, int priority) {
|
||||||
|
return EntityController.getFor(entity)
|
||||||
|
.addTargetGoal(priority, this)
|
||||||
|
.getEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalDefendVillage;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalHurtBy;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalNearestAttackable;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalNearestAttackableWitch;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalNearestHealableRaider;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalNonTameRandom;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalOwnerHurtBy;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalOwnerTarget;
|
||||||
|
import com.willfp.eco.core.entities.ai.target.TargetGoalResetUniversalAnger;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to manage target goals.
|
||||||
|
*/
|
||||||
|
public final class TargetGoals {
|
||||||
|
/**
|
||||||
|
* All registered deserializers.
|
||||||
|
*/
|
||||||
|
private static final Map<NamespacedKey, KeyedDeserializer<? extends TargetGoal<?>>> BY_KEY = HashBiMap.create();
|
||||||
|
|
||||||
|
static {
|
||||||
|
register(TargetGoalDefendVillage.DESERIALIZER);
|
||||||
|
register(TargetGoalHurtBy.DESERIALIZER);
|
||||||
|
register(TargetGoalNearestAttackable.DESERIALIZER);
|
||||||
|
register(TargetGoalNearestAttackableWitch.DESERIALIZER);
|
||||||
|
register(TargetGoalNearestHealableRaider.DESERIALIZER);
|
||||||
|
register(TargetGoalNonTameRandom.DESERIALIZER);
|
||||||
|
register(TargetGoalOwnerTarget.DESERIALIZER);
|
||||||
|
register(TargetGoalOwnerHurtBy.DESERIALIZER);
|
||||||
|
register(TargetGoalResetUniversalAnger.DESERIALIZER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get deserializer by key.
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @return The deserializer, or null if not found.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static KeyedDeserializer<? extends TargetGoal<? extends Mob>> getByKey(@NotNull final NamespacedKey key) {
|
||||||
|
return BY_KEY.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get deserializer by key, with a defined type (to prevent cluttering code with unsafe casts).
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @param clazz The type of target goal.
|
||||||
|
* @param <T> The type of mob the goal can be applied to.
|
||||||
|
* @return The deserializer, or null if not found.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@SuppressWarnings({"unchecked", "unused"})
|
||||||
|
public static <T extends Mob> KeyedDeserializer<TargetGoal<T>> getByKeyOfType(@NotNull final NamespacedKey key,
|
||||||
|
@NotNull final Class<T> clazz) {
|
||||||
|
return (KeyedDeserializer<TargetGoal<T>>) BY_KEY.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply goal to entity given key and config.
|
||||||
|
* <p>
|
||||||
|
* If the key or config are invalid, the goal will not be applied.
|
||||||
|
*
|
||||||
|
* @param entity The entity.
|
||||||
|
* @param key The key.
|
||||||
|
* @param config The config.
|
||||||
|
* @param priority The priority.
|
||||||
|
* @param <T> The entity type.
|
||||||
|
* @return The entity.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Mob> T applyToEntity(@NotNull final T entity,
|
||||||
|
@NotNull final NamespacedKey key,
|
||||||
|
@NotNull final Config config,
|
||||||
|
final int priority) {
|
||||||
|
KeyedDeserializer<TargetGoal<T>> deserializer = getByKeyOfType(key, (Class<T>) entity.getClass());
|
||||||
|
if (deserializer == null) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetGoal<T> goal = deserializer.deserialize(config);
|
||||||
|
|
||||||
|
if (goal == null) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return goal.addToEntity(entity, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a deserializer for a target goal.
|
||||||
|
*
|
||||||
|
* @param toRegister The target goal to register.
|
||||||
|
* @param <T> The type of deserializer.
|
||||||
|
* @return The deserializer.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T extends KeyedDeserializer<? extends TargetGoal<?>>> T register(@NotNull final T toRegister) {
|
||||||
|
BY_KEY.put(toRegister.getKey(), toRegister);
|
||||||
|
return toRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TargetGoals() {
|
||||||
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avoid entities.
|
||||||
|
*
|
||||||
|
* @param entity The entity type to avoid.
|
||||||
|
* @param distance The distance to flee to.
|
||||||
|
* @param slowSpeed The slow movement speed.
|
||||||
|
* @param fastSpeed The fast movement speed.
|
||||||
|
*/
|
||||||
|
public record EntityGoalAvoidEntity(
|
||||||
|
@NotNull TestableEntity entity,
|
||||||
|
double distance,
|
||||||
|
double slowSpeed,
|
||||||
|
double fastSpeed
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalAvoidEntity> DESERIALIZER = new Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalAvoidEntity> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalAvoidEntity deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("entity")
|
||||||
|
&& config.has("distance")
|
||||||
|
&& config.has("slowSpeed")
|
||||||
|
&& config.has("fastSpeed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TestableEntity entity = Entities.lookup(config.getString("entity"));
|
||||||
|
|
||||||
|
return new EntityGoalAvoidEntity(
|
||||||
|
entity,
|
||||||
|
config.getDouble("distance"),
|
||||||
|
config.getDouble("slowSpeed"),
|
||||||
|
config.getDouble("fastSpeed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("avoid_entity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to break down doors.
|
||||||
|
*
|
||||||
|
* @param ticks The time taken to break the door. Minimum value is 240, as set by the game.
|
||||||
|
*/
|
||||||
|
public record EntityGoalBreakDoors(
|
||||||
|
int ticks
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalBreakDoors> DESERIALIZER = new EntityGoalBreakDoors.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalBreakDoors> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalBreakDoors deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("ticks")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalBreakDoors(
|
||||||
|
config.getInt("ticks")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("break_doors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Breathe air.
|
||||||
|
*/
|
||||||
|
public record EntityGoalBreatheAir(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalBreatheAir> DESERIALIZER = new EntityGoalBreatheAir.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalBreatheAir> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalBreatheAir deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalBreatheAir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("breathe_air");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Animals;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows animals to breed.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move to a partner.
|
||||||
|
*/
|
||||||
|
public record EntityGoalBreed(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Animals> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalBreed> DESERIALIZER = new EntityGoalBreed.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalBreed> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalBreed deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalBreed(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("breed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Cat;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a cat to lie on a bed.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move to the bed.
|
||||||
|
* @param range The range at which to search for beds.
|
||||||
|
*/
|
||||||
|
public record EntityGoalCatLieOnBed(
|
||||||
|
double speed,
|
||||||
|
int range
|
||||||
|
) implements EntityGoal<Cat> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalCatLieOnBed> DESERIALIZER = new EntityGoalCatLieOnBed.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalCatLieOnBed> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalCatLieOnBed deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("range")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalCatLieOnBed(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getInt("range")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("cat_lie_on_bed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Cat;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a cat to sit on a bed.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move to the bed.
|
||||||
|
*/
|
||||||
|
public record EntityGoalCatSitOnBed(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Cat> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalCatSitOnBed> DESERIALIZER = new EntityGoalCatSitOnBed.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalCatSitOnBed> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalCatSitOnBed deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalCatSitOnBed(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("cat_sit_on_bed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to eat the ground.
|
||||||
|
*/
|
||||||
|
public record EntityGoalEatGrass(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalEatGrass> DESERIALIZER = new EntityGoalEatGrass.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalEatGrass> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalEatGrass deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalEatGrass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("eat_grass");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will make the entity actively avoid the sunlight.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to flee.
|
||||||
|
*/
|
||||||
|
public record EntityGoalFleeSun(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalFleeSun> DESERIALIZER = new EntityGoalFleeSun.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalFleeSun> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalFleeSun deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalFleeSun(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("flee_sun");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to float on water.
|
||||||
|
*/
|
||||||
|
public record EntityGoalFloat(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalFloat> DESERIALIZER = new EntityGoalFloat.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalFloat> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalFloat deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("float");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Follow boats.
|
||||||
|
*/
|
||||||
|
public record EntityGoalFollowBoats(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalFollowBoats> DESERIALIZER = new EntityGoalFollowBoats.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalFollowBoats> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalFollowBoats deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalFollowBoats();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("follow_boats");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to follow and gather around all types of mobs, both hostile and neutral mobs.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to follow.
|
||||||
|
* @param minDistance The minimum follow distance.
|
||||||
|
* @param maxDistance The maximum follow distance.
|
||||||
|
*/
|
||||||
|
public record EntityGoalFollowMobs(
|
||||||
|
double speed,
|
||||||
|
double minDistance,
|
||||||
|
double maxDistance
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalFollowMobs> DESERIALIZER = new EntityGoalFollowMobs.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalFollowMobs> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalFollowMobs deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("minDistance")
|
||||||
|
&& config.has("maxDistance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalFollowMobs(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getDouble("minDistance"),
|
||||||
|
config.getDouble("maxDistance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("follow_mobs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Illusioner;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an illusioner to perform the blindness spell.
|
||||||
|
*/
|
||||||
|
public record EntityGoalIllusionerBlindnessSpell(
|
||||||
|
) implements EntityGoal<Illusioner> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalIllusionerBlindnessSpell> DESERIALIZER = new EntityGoalIllusionerBlindnessSpell.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalIllusionerBlindnessSpell> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalIllusionerBlindnessSpell deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalIllusionerBlindnessSpell();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("illusioner_blindness_spell");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Illusioner;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an illusioner to perform the mirror spell.
|
||||||
|
*/
|
||||||
|
public record EntityGoalIllusionerMirrorSpell(
|
||||||
|
) implements EntityGoal<Illusioner> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalIllusionerMirrorSpell> DESERIALIZER = new EntityGoalIllusionerMirrorSpell.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalIllusionerMirrorSpell> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalIllusionerMirrorSpell deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalIllusionerMirrorSpell();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("illusioner_mirror_spell");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interact with other mobs.
|
||||||
|
*
|
||||||
|
* @param target The type of entity to interact with.
|
||||||
|
* @param range The range at which to interact.
|
||||||
|
* @param chance The chance for interaction, between 0 and 1.
|
||||||
|
*/
|
||||||
|
public record EntityGoalInteract(
|
||||||
|
@NotNull TestableEntity target,
|
||||||
|
double range,
|
||||||
|
double chance
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalInteract> DESERIALIZER = new EntityGoalInteract.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalInteract> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalInteract deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("target")
|
||||||
|
&& config.has("range")
|
||||||
|
&& config.has("chance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalInteract(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getDouble("range"),
|
||||||
|
config.getDouble("chance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("interact");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to jump towards a target.
|
||||||
|
*
|
||||||
|
* @param velocity The leap velocity.
|
||||||
|
*/
|
||||||
|
public record EntityGoalLeapAtTarget(
|
||||||
|
double velocity
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalLeapAtTarget> DESERIALIZER = new EntityGoalLeapAtTarget.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalLeapAtTarget> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalLeapAtTarget deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("velocity")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalLeapAtTarget(
|
||||||
|
config.getDouble("velocity")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("leap_at_target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to look at the player by rotating the head bone pose within a set limit.
|
||||||
|
*
|
||||||
|
* @param range The range at which to look at the player.
|
||||||
|
* @param chance The chance to look at the player, between 0 and 1.
|
||||||
|
*/
|
||||||
|
public record EntityGoalLookAtPlayer(
|
||||||
|
double range,
|
||||||
|
double chance
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalLookAtPlayer> DESERIALIZER = new EntityGoalLookAtPlayer.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalLookAtPlayer> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalLookAtPlayer deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("range")
|
||||||
|
&& config.has("chance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalLookAtPlayer(
|
||||||
|
config.getDouble("range"),
|
||||||
|
config.getDouble("chance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("look_at_player");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows entities to make close combat melee attacks.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to attack the target.
|
||||||
|
* @param pauseWhenMobIdle If the entity should pause attacking when the target is idle.
|
||||||
|
*/
|
||||||
|
public record EntityGoalMeleeAttack(
|
||||||
|
double speed,
|
||||||
|
boolean pauseWhenMobIdle
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalMeleeAttack> DESERIALIZER = new EntityGoalMeleeAttack.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalMeleeAttack> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalMeleeAttack deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("pauseWhenMobIdle")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalMeleeAttack(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getBool("pauseWhenMobIdle")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("melee_attack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to navigate and search for a nearby village.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move back to the village.
|
||||||
|
* @param canDespawn If the entity can despawn.
|
||||||
|
*/
|
||||||
|
public record EntityGoalMoveBackToVillage(
|
||||||
|
double speed,
|
||||||
|
boolean canDespawn
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalMoveBackToVillage> DESERIALIZER = new EntityGoalMoveBackToVillage.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalMoveBackToVillage> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalMoveBackToVillage deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("canDespawn")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalMoveBackToVillage(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getBool("canDespawn")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("move_back_to_village");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the entity to create paths around the village.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move through the village.
|
||||||
|
* @param onlyAtNight If the entity can only move through village at night.
|
||||||
|
* @param distance The distance to move through the village.
|
||||||
|
* @param canPassThroughDoors If the entity can pass through doors.
|
||||||
|
*/
|
||||||
|
public record EntityGoalMoveThroughVillage(
|
||||||
|
double speed,
|
||||||
|
boolean onlyAtNight,
|
||||||
|
int distance,
|
||||||
|
boolean canPassThroughDoors
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalMoveThroughVillage> DESERIALIZER = new EntityGoalMoveThroughVillage.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalMoveThroughVillage> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalMoveThroughVillage deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("onlyAtNight")
|
||||||
|
&& config.has("distance")
|
||||||
|
&& config.has("canPassThroughDoors")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalMoveThroughVillage(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getBool("onlyAtNight"),
|
||||||
|
config.getInt("distance"),
|
||||||
|
config.getBool("canPassThroughDoors")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("move_through_village");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move towards restriction.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move towards the restriction.
|
||||||
|
*/
|
||||||
|
public record EntityGoalMoveTowardsRestriction(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalMoveTowardsRestriction> DESERIALIZER = new EntityGoalMoveTowardsRestriction.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalMoveTowardsRestriction> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalMoveTowardsRestriction deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalMoveTowardsRestriction(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("move_towards_restriction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to move towards a target.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move towards the target.
|
||||||
|
* @param maxDistance The maximum distance the target can be where the entity will still move towards it.
|
||||||
|
*/
|
||||||
|
public record EntityGoalMoveTowardsTarget(
|
||||||
|
double speed,
|
||||||
|
double maxDistance
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalMoveTowardsTarget> DESERIALIZER = new EntityGoalMoveTowardsTarget.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalMoveTowardsTarget> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalMoveTowardsTarget deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("maxDistance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalMoveTowardsTarget(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getDouble("maxDistance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("move_towards_target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attack like an ocelot.
|
||||||
|
*/
|
||||||
|
public record EntityGoalOcelotAttack(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalOcelotAttack> DESERIALIZER = new EntityGoalOcelotAttack.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalOcelotAttack> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalOcelotAttack deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalOcelotAttack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("ocelot_attack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to interact and open a door.
|
||||||
|
*
|
||||||
|
* @param delayClosing If closing the door should be delayed.
|
||||||
|
*/
|
||||||
|
public record EntityGoalOpenDoors(
|
||||||
|
boolean delayClosing
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalOpenDoors> DESERIALIZER = new EntityGoalOpenDoors.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalOpenDoors> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalOpenDoors deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("delayClosing")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalOpenDoors(
|
||||||
|
config.getBool("delayClosing")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("open_doors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to react when it receives damage.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to panic.
|
||||||
|
*/
|
||||||
|
public record EntityGoalPanic(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalPanic> DESERIALIZER = new EntityGoalPanic.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalPanic> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalPanic deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalPanic(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("panic");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to choose a random direction to look in for a random duration within a range.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRandomLookAround(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRandomLookAround> DESERIALIZER = new EntityGoalRandomLookAround.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRandomLookAround> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalRandomLookAround deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalRandomLookAround();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("random_look_around");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to choose a random direction to walk towards.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move around.
|
||||||
|
* @param interval The amount of ticks to wait (on average) between strolling around.
|
||||||
|
* @param canDespawn If the entity can despawn.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRandomStroll(
|
||||||
|
double speed,
|
||||||
|
int interval,
|
||||||
|
boolean canDespawn
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRandomStroll> DESERIALIZER = new EntityGoalRandomStroll.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRandomStroll> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalRandomStroll deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("interval")
|
||||||
|
&& config.has("canDespawn")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalRandomStroll(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getInt("interval"),
|
||||||
|
config.getBool("canDespawn")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("random_stroll");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to swim in a random point in water.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which to move around.
|
||||||
|
* @param interval The amount of ticks to wait (on average) between strolling around.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRandomSwimming(
|
||||||
|
double speed,
|
||||||
|
int interval
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRandomSwimming> DESERIALIZER = new EntityGoalRandomSwimming.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRandomSwimming> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalRandomSwimming deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("interval")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalRandomSwimming(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getInt("interval")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("random_swimming");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ranged attack.
|
||||||
|
* <p>
|
||||||
|
* Only supports mobs that have ranged attacks.
|
||||||
|
*
|
||||||
|
* @param speed The speed.
|
||||||
|
* @param minInterval The minimum interval between attacks (in ticks).
|
||||||
|
* @param maxInterval The maximum interval between attacks (in ticks).
|
||||||
|
* @param maxRange The max range at which to attack.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRangedAttack(
|
||||||
|
double speed,
|
||||||
|
int minInterval,
|
||||||
|
int maxInterval,
|
||||||
|
double maxRange
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRangedAttack> DESERIALIZER = new EntityGoalRangedAttack.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRangedAttack> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalRangedAttack deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("minInterval")
|
||||||
|
&& config.has("maxInterval")
|
||||||
|
&& config.has("range")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalRangedAttack(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getInt("minInterval"),
|
||||||
|
config.getInt("maxInterval"),
|
||||||
|
config.getDouble("range")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("ranged_attack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Monster;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ranged attack.
|
||||||
|
* <p>
|
||||||
|
* Only supports monsters that have bow attacks.
|
||||||
|
*
|
||||||
|
* @param speed The speed.
|
||||||
|
* @param interval The interval between attacks (in ticks).
|
||||||
|
* @param range The max range at which to attack.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRangedBowAttack(
|
||||||
|
double speed,
|
||||||
|
int interval,
|
||||||
|
double range
|
||||||
|
) implements EntityGoal<Monster> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRangedBowAttack> DESERIALIZER = new EntityGoalRangedBowAttack.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRangedBowAttack> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalRangedBowAttack deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("interval")
|
||||||
|
&& config.has("range")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalRangedBowAttack(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getInt("interval"),
|
||||||
|
config.getDouble("range")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("ranged_bow_attack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Monster;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ranged attack.
|
||||||
|
* <p>
|
||||||
|
* Only supports monsters that have crossbow attacks.
|
||||||
|
*
|
||||||
|
* @param speed The speed.
|
||||||
|
* @param range The max range at which to attack.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRangedCrossbowAttack(
|
||||||
|
double speed,
|
||||||
|
double range
|
||||||
|
) implements EntityGoal<Monster> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRangedCrossbowAttack> DESERIALIZER = new EntityGoalRangedCrossbowAttack.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRangedCrossbowAttack> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalRangedCrossbowAttack deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("range")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalRangedCrossbowAttack(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getDouble("range")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("ranged_crossbow_attack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to actively avoid direct sunlight.
|
||||||
|
*/
|
||||||
|
public record EntityGoalRestrictSun(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalRestrictSun> DESERIALIZER = new EntityGoalRestrictSun.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalRestrictSun> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalRestrictSun deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalRestrictSun();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("restrict_sun");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the entity to create paths around the village.
|
||||||
|
*
|
||||||
|
* @param searchRange The search range.
|
||||||
|
*/
|
||||||
|
public record EntityGoalStrollThroughVillage(
|
||||||
|
int searchRange
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalStrollThroughVillage> DESERIALIZER = new EntityGoalStrollThroughVillage.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalStrollThroughVillage> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalStrollThroughVillage deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("searchRange")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalStrollThroughVillage(
|
||||||
|
config.getInt("searchRange")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("stroll_through_village");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.items.Items;
|
||||||
|
import com.willfp.eco.core.items.TestableItem;
|
||||||
|
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to be tempted by a set item.
|
||||||
|
*
|
||||||
|
* @param speed The speed at which the entity follows the item.
|
||||||
|
* @param items The items that the entity will be attracted by.
|
||||||
|
* @param canBeScared If the entity can be scared and lose track of the item.
|
||||||
|
*/
|
||||||
|
public record EntityGoalTempt(
|
||||||
|
double speed,
|
||||||
|
@NotNull Collection<TestableItem> items,
|
||||||
|
boolean canBeScared
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* @param speed The speed at which the entity follows the item.
|
||||||
|
* @param item The item that the entity will be attracted by.
|
||||||
|
* @param canBeScared If the entity can be scared and lose track of the item.
|
||||||
|
*/
|
||||||
|
public EntityGoalTempt(final double speed,
|
||||||
|
@NotNull final TestableItem item,
|
||||||
|
final boolean canBeScared) {
|
||||||
|
this(speed, List.of(item), canBeScared);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalTempt> DESERIALIZER = new EntityGoalTempt.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalTempt> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalTempt deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("items")
|
||||||
|
&& config.has("canBeScared")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Collection<TestableItem> items = config.getStrings("items").stream()
|
||||||
|
.map(Items::lookup)
|
||||||
|
.filter(it -> !(it instanceof EmptyTestableItem))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return new EntityGoalTempt(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
items,
|
||||||
|
config.getBool("canBeScared")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("tempt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to move to water when on land.
|
||||||
|
*/
|
||||||
|
public record EntityGoalTryFindWater(
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalTryFindWater> DESERIALIZER = new EntityGoalTryFindWater.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalTryFindWater> {
|
||||||
|
@Override
|
||||||
|
public EntityGoalTryFindWater deserialize(@NotNull final Config config) {
|
||||||
|
return new EntityGoalTryFindWater();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("try_find_water");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.items.Items;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use item.
|
||||||
|
*
|
||||||
|
* @param item The item.
|
||||||
|
* @param sound The sound to play on use.
|
||||||
|
* @param condition The condition when to use the item.
|
||||||
|
*/
|
||||||
|
public record EntityGoalUseItem(
|
||||||
|
@NotNull ItemStack item,
|
||||||
|
@NotNull Sound sound,
|
||||||
|
@NotNull Predicate<LivingEntity> condition
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalUseItem> DESERIALIZER = new EntityGoalUseItem.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalUseItem> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalUseItem deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("item")
|
||||||
|
&& config.has("sound")
|
||||||
|
&& config.has("condition")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TestableEntity filter = Entities.lookup(config.getString("condition"));
|
||||||
|
|
||||||
|
return new EntityGoalUseItem(
|
||||||
|
Items.lookup(config.getString("item")).getItem(),
|
||||||
|
Sound.valueOf(config.getString("sound").toUpperCase()),
|
||||||
|
filter::matches
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("use_item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fly randomly while avoiding water.
|
||||||
|
*
|
||||||
|
* @param speed The speed.
|
||||||
|
*/
|
||||||
|
public record EntityGoalWaterAvoidingRandomFlying(
|
||||||
|
double speed
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalWaterAvoidingRandomFlying> DESERIALIZER = new EntityGoalWaterAvoidingRandomFlying.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalWaterAvoidingRandomFlying> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalWaterAvoidingRandomFlying deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalWaterAvoidingRandomFlying(
|
||||||
|
config.getDouble("speed")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("water_avoiding_random_flying");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stroll randomly while avoiding water.
|
||||||
|
*
|
||||||
|
* @param speed The speed.
|
||||||
|
* @param chance The chance to stroll every tick, between 0 and 1.
|
||||||
|
*/
|
||||||
|
public record EntityGoalWaterAvoidingRandomStroll(
|
||||||
|
double speed,
|
||||||
|
double chance
|
||||||
|
) implements EntityGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalWaterAvoidingRandomStroll> DESERIALIZER = new EntityGoalWaterAvoidingRandomStroll.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalWaterAvoidingRandomStroll> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalWaterAvoidingRandomStroll deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("speed")
|
||||||
|
&& config.has("chance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalWaterAvoidingRandomStroll(
|
||||||
|
config.getDouble("speed"),
|
||||||
|
config.getDouble("chance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("water_avoiding_random_stroll");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.entity;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Wolf;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a wolf to beg.
|
||||||
|
*
|
||||||
|
* @param distance The distance at which to beg from.
|
||||||
|
*/
|
||||||
|
public record EntityGoalWolfBeg(
|
||||||
|
double distance
|
||||||
|
) implements EntityGoal<Wolf> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<EntityGoalWolfBeg> DESERIALIZER = new EntityGoalWolfBeg.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<EntityGoalWolfBeg> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public EntityGoalWolfBeg deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("distance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new EntityGoalWolfBeg(
|
||||||
|
config.getDouble("distance")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("wolf_beg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.IronGolem;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defend village.
|
||||||
|
*/
|
||||||
|
public record TargetGoalDefendVillage(
|
||||||
|
) implements TargetGoal<IronGolem> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalDefendVillage> DESERIALIZER = new TargetGoalDefendVillage.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalDefendVillage> {
|
||||||
|
@Override
|
||||||
|
public TargetGoalDefendVillage deserialize(@NotNull final Config config) {
|
||||||
|
return new TargetGoalDefendVillage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("defend_village");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to react when hit by set target.
|
||||||
|
*
|
||||||
|
* @param blacklist The entities not to attack when hurt by.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"varargs"})
|
||||||
|
public record TargetGoalHurtBy(
|
||||||
|
@NotNull TestableEntity blacklist
|
||||||
|
) implements TargetGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalHurtBy> DESERIALIZER = new TargetGoalHurtBy.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalHurtBy> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalHurtBy deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("blacklist")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new TargetGoalHurtBy(
|
||||||
|
Entities.lookup(config.getString("blacklist"))
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("hurt_by");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Raider;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to attack the closest target within a given subset of specific target types.
|
||||||
|
*
|
||||||
|
* @param target The type of entities to attack.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param checkCanNavigate If navigation should be checked.
|
||||||
|
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
|
||||||
|
* @param targetFilter The filter for targets to match.
|
||||||
|
*/
|
||||||
|
public record TargetGoalNearestAttackable(
|
||||||
|
@NotNull TestableEntity target,
|
||||||
|
boolean checkVisibility,
|
||||||
|
boolean checkCanNavigate,
|
||||||
|
int reciprocalChance,
|
||||||
|
@NotNull Predicate<LivingEntity> targetFilter
|
||||||
|
) implements TargetGoal<Raider> {
|
||||||
|
/**
|
||||||
|
* @param target The type of entities to attack.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param checkCanNavigate If navigation should be checked.
|
||||||
|
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
|
||||||
|
*/
|
||||||
|
public TargetGoalNearestAttackable(@NotNull final TestableEntity target,
|
||||||
|
final boolean checkVisibility,
|
||||||
|
final boolean checkCanNavigate,
|
||||||
|
final int reciprocalChance) {
|
||||||
|
this(target, checkVisibility, checkCanNavigate, reciprocalChance, it -> true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalNearestAttackable> DESERIALIZER = new TargetGoalNearestAttackable.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestAttackable> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalNearestAttackable deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("target")
|
||||||
|
&& config.has("checkVisibility")
|
||||||
|
&& config.has("checkCanNavigate")
|
||||||
|
&& config.has("reciprocalChance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (config.has("targetFilter")) {
|
||||||
|
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
|
||||||
|
|
||||||
|
return new TargetGoalNearestAttackable(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
config.getBool("checkCanNavigate"),
|
||||||
|
config.getInt("reciprocalChance"),
|
||||||
|
filter::matches
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new TargetGoalNearestAttackable(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
config.getBool("checkCanNavigate"),
|
||||||
|
config.getInt("reciprocalChance")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("nearest_attackable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Raider;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to attack the closest target within a given subset of specific target types.
|
||||||
|
*
|
||||||
|
* @param target The type of entities to attack.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param checkCanNavigate If navigation should be checked.
|
||||||
|
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
|
||||||
|
* @param targetFilter The filter for targets to match.
|
||||||
|
*/
|
||||||
|
public record TargetGoalNearestAttackableWitch(
|
||||||
|
@NotNull TestableEntity target,
|
||||||
|
boolean checkVisibility,
|
||||||
|
boolean checkCanNavigate,
|
||||||
|
int reciprocalChance,
|
||||||
|
@NotNull Predicate<LivingEntity> targetFilter
|
||||||
|
) implements TargetGoal<Raider> {
|
||||||
|
/**
|
||||||
|
* @param target The type of entities to attack.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param checkCanNavigate If navigation should be checked.
|
||||||
|
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
|
||||||
|
*/
|
||||||
|
public TargetGoalNearestAttackableWitch(@NotNull final TestableEntity target,
|
||||||
|
final boolean checkVisibility,
|
||||||
|
final boolean checkCanNavigate,
|
||||||
|
final int reciprocalChance) {
|
||||||
|
this(target, checkVisibility, checkCanNavigate, reciprocalChance, it -> true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalNearestAttackableWitch> DESERIALIZER = new TargetGoalNearestAttackableWitch.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestAttackableWitch> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalNearestAttackableWitch deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("target")
|
||||||
|
&& config.has("checkVisibility")
|
||||||
|
&& config.has("checkCanNavigate")
|
||||||
|
&& config.has("reciprocalChance")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (config.has("targetFilter")) {
|
||||||
|
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
|
||||||
|
|
||||||
|
return new TargetGoalNearestAttackableWitch(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
config.getBool("checkCanNavigate"),
|
||||||
|
config.getInt("reciprocalChance"),
|
||||||
|
filter::matches
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new TargetGoalNearestAttackableWitch(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
config.getBool("checkCanNavigate"),
|
||||||
|
config.getInt("reciprocalChance")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("nearest_attackable_witch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Raider;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target nearest attackable raider.
|
||||||
|
*
|
||||||
|
* @param target The types of entities to heal.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param targetFilter The filter for targets to match.
|
||||||
|
*/
|
||||||
|
public record TargetGoalNearestHealableRaider(
|
||||||
|
@NotNull TestableEntity target,
|
||||||
|
boolean checkVisibility,
|
||||||
|
@NotNull Predicate<LivingEntity> targetFilter
|
||||||
|
) implements TargetGoal<Raider> {
|
||||||
|
/**
|
||||||
|
* @param target The target.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
*/
|
||||||
|
public TargetGoalNearestHealableRaider(@NotNull final TestableEntity target,
|
||||||
|
final boolean checkVisibility) {
|
||||||
|
this(target, checkVisibility, it -> true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalNearestHealableRaider> DESERIALIZER = new TargetGoalNearestHealableRaider.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestHealableRaider> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalNearestHealableRaider deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("target")
|
||||||
|
&& config.has("checkVisibility")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (config.has("targetFilter")) {
|
||||||
|
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
|
||||||
|
|
||||||
|
return new TargetGoalNearestHealableRaider(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
filter::matches
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new TargetGoalNearestHealableRaider(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("nearest_healable_raider");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.Entities;
|
||||||
|
import com.willfp.eco.core.entities.TestableEntity;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Tameable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target random non-tame entity.
|
||||||
|
*
|
||||||
|
* @param target The types of entities to heal.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
* @param targetFilter The filter for targets to match.
|
||||||
|
*/
|
||||||
|
public record TargetGoalNonTameRandom(
|
||||||
|
@NotNull TestableEntity target,
|
||||||
|
boolean checkVisibility,
|
||||||
|
@NotNull Predicate<LivingEntity> targetFilter
|
||||||
|
) implements TargetGoal<Tameable> {
|
||||||
|
/**
|
||||||
|
* @param target The types of entities to heal.
|
||||||
|
* @param checkVisibility If visibility should be checked.
|
||||||
|
*/
|
||||||
|
public TargetGoalNonTameRandom(@NotNull final TestableEntity target,
|
||||||
|
final boolean checkVisibility) {
|
||||||
|
this(target, checkVisibility, it -> true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalNonTameRandom> DESERIALIZER = new TargetGoalNonTameRandom.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalNonTameRandom> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalNonTameRandom deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("targetClass")
|
||||||
|
&& config.has("checkVisibility")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (config.has("targetFilter")) {
|
||||||
|
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
|
||||||
|
|
||||||
|
return new TargetGoalNonTameRandom(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility"),
|
||||||
|
filter::matches
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new TargetGoalNonTameRandom(
|
||||||
|
Entities.lookup(config.getString("target")),
|
||||||
|
config.getBool("checkVisibility")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("non_tame_random");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Tameable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to react when the owner is hit by a target.
|
||||||
|
*/
|
||||||
|
public record TargetGoalOwnerHurtBy(
|
||||||
|
) implements TargetGoal<Tameable> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalOwnerHurtBy> DESERIALIZER = new TargetGoalOwnerHurtBy.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalOwnerHurtBy> {
|
||||||
|
@Override
|
||||||
|
public TargetGoalOwnerHurtBy deserialize(@NotNull final Config config) {
|
||||||
|
return new TargetGoalOwnerHurtBy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("owner_hurt_by");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Tameable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an entity to react when the owner hits a target.
|
||||||
|
*/
|
||||||
|
public record TargetGoalOwnerTarget(
|
||||||
|
) implements TargetGoal<Tameable> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalOwnerTarget> DESERIALIZER = new TargetGoalOwnerTarget.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalOwnerTarget> {
|
||||||
|
@Override
|
||||||
|
public TargetGoalOwnerTarget deserialize(@NotNull final Config config) {
|
||||||
|
return new TargetGoalOwnerTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("owner_target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.willfp.eco.core.entities.ai.target;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal;
|
||||||
|
import com.willfp.eco.core.serialization.KeyedDeserializer;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Mob;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset universal anger.
|
||||||
|
* <p>
|
||||||
|
* Can only be applied to neutral mobs.
|
||||||
|
*
|
||||||
|
* @param triggerOthers If this should cause other nearby entities to trigger.
|
||||||
|
*/
|
||||||
|
public record TargetGoalResetUniversalAnger(
|
||||||
|
boolean triggerOthers
|
||||||
|
) implements TargetGoal<Mob> {
|
||||||
|
/**
|
||||||
|
* The deserializer for the goal.
|
||||||
|
*/
|
||||||
|
public static final KeyedDeserializer<TargetGoalResetUniversalAnger> DESERIALIZER = new TargetGoalResetUniversalAnger.Deserializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize configs into the goal.
|
||||||
|
*/
|
||||||
|
private static final class Deserializer implements KeyedDeserializer<TargetGoalResetUniversalAnger> {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public TargetGoalResetUniversalAnger deserialize(@NotNull final Config config) {
|
||||||
|
if (!(
|
||||||
|
config.has("triggerOthers")
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new TargetGoalResetUniversalAnger(
|
||||||
|
config.getBool("triggerOthers")
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
Exceptions could be caused by configs having values of a wrong type,
|
||||||
|
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
|
||||||
|
so we encapsulate them as null.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return NamespacedKey.minecraft("reset_universal_anger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,6 +96,13 @@ public interface Menu {
|
|||||||
*/
|
*/
|
||||||
Set<NamespacedKey> getKeys(@NotNull Player player);
|
Set<NamespacedKey> getKeys(@NotNull Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-render the menu for a player.
|
||||||
|
*
|
||||||
|
* @param player The player.
|
||||||
|
*/
|
||||||
|
void refresh(@NotNull Player player);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a builder with a given amount of rows.
|
* Create a builder with a given amount of rows.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package com.willfp.eco.core.integrations.placeholder;
|
package com.willfp.eco.core.integrations.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.placeholder.Placeholder;
|
||||||
|
import com.willfp.eco.core.placeholder.PlayerPlaceholder;
|
||||||
|
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -10,10 +14,13 @@ import java.util.Objects;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link PlaceholderEntry} is a placeholder in and of itself.
|
* A placeholder entry is a placeholder in and of itself.
|
||||||
* <p>
|
* <p>
|
||||||
* It should be fairly straightforward.
|
* It should be fairly straightforward.
|
||||||
|
*
|
||||||
|
* @deprecated Confusing functionality with inconsistent nullability and poor naming.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.28.0", forRemoval = true)
|
||||||
public class PlaceholderEntry {
|
public class PlaceholderEntry {
|
||||||
/**
|
/**
|
||||||
* The name of the placeholder, used in lookups.
|
* The name of the placeholder, used in lookups.
|
||||||
@@ -140,7 +147,28 @@ public class PlaceholderEntry {
|
|||||||
* Register the placeholder.
|
* Register the placeholder.
|
||||||
*/
|
*/
|
||||||
public void register() {
|
public void register() {
|
||||||
PlaceholderManager.registerPlaceholder(this);
|
PlaceholderManager.registerPlaceholder(this.toModernPlaceholder());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the placeholder to a modern placeholder.
|
||||||
|
*
|
||||||
|
* @return The placeholder.
|
||||||
|
*/
|
||||||
|
Placeholder toModernPlaceholder() {
|
||||||
|
if (this.requiresPlayer) {
|
||||||
|
return new PlayerPlaceholder(
|
||||||
|
Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()),
|
||||||
|
identifier,
|
||||||
|
function
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new PlayerlessPlaceholder(
|
||||||
|
Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()),
|
||||||
|
identifier,
|
||||||
|
() -> function.apply(null)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
|||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
import com.willfp.eco.core.Eco;
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.placeholder.Placeholder;
|
||||||
|
import com.willfp.eco.core.placeholder.PlayerPlaceholder;
|
||||||
|
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -19,11 +24,12 @@ import java.util.concurrent.TimeUnit;
|
|||||||
/**
|
/**
|
||||||
* Class to handle placeholder integrations.
|
* Class to handle placeholder integrations.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("removal")
|
||||||
public final class PlaceholderManager {
|
public final class PlaceholderManager {
|
||||||
/**
|
/**
|
||||||
* All registered placeholders.
|
* All registered placeholders.
|
||||||
*/
|
*/
|
||||||
private static final Map<EcoPlugin, Map<String, PlaceholderEntry>> REGISTERED_PLACEHOLDERS = new HashMap<>();
|
private static final Map<EcoPlugin, Map<String, Placeholder>> REGISTERED_PLACEHOLDERS = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All registered placeholder integrations.
|
* All registered placeholder integrations.
|
||||||
@@ -35,7 +41,7 @@ public final class PlaceholderManager {
|
|||||||
*/
|
*/
|
||||||
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
|
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||||
.build(key -> key.entry.getResult(key.player));
|
.build(key -> key.entry.getValue(key.player));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new placeholder integration.
|
* Register a new placeholder integration.
|
||||||
@@ -50,16 +56,31 @@ public final class PlaceholderManager {
|
|||||||
/**
|
/**
|
||||||
* Register a placeholder.
|
* Register a placeholder.
|
||||||
*
|
*
|
||||||
* @param expansion The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderEntry} to register.
|
* @param placeholder The placeholder to register.
|
||||||
*/
|
*/
|
||||||
public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) {
|
public static void registerPlaceholder(@NotNull final Placeholder placeholder) {
|
||||||
EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
|
if (placeholder instanceof StaticPlaceholder) {
|
||||||
Map<String, PlaceholderEntry> pluginPlaceholders = REGISTERED_PLACEHOLDERS
|
throw new IllegalArgumentException("Static placeholders cannot be registered!");
|
||||||
|
}
|
||||||
|
|
||||||
|
EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : placeholder.getPlugin();
|
||||||
|
Map<String, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
|
||||||
.getOrDefault(plugin, new HashMap<>());
|
.getOrDefault(plugin, new HashMap<>());
|
||||||
pluginPlaceholders.put(expansion.getIdentifier(), expansion);
|
pluginPlaceholders.put(placeholder.getIdentifier(), placeholder);
|
||||||
REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders);
|
REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a placeholder.
|
||||||
|
*
|
||||||
|
* @param placeholder The placeholder to register.
|
||||||
|
* @deprecated Uses old placeholder system.
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "6.28.0", forRemoval = true)
|
||||||
|
public static void registerPlaceholder(@NotNull final PlaceholderEntry placeholder) {
|
||||||
|
registerPlaceholder(placeholder.toModernPlaceholder());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the result of a placeholder with respect to a player.
|
* Get the result of a placeholder with respect to a player.
|
||||||
*
|
*
|
||||||
@@ -82,29 +103,36 @@ public final class PlaceholderManager {
|
|||||||
* @param plugin The plugin for the placeholder.
|
* @param plugin The plugin for the placeholder.
|
||||||
* @return The value of the placeholder.
|
* @return The value of the placeholder.
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
public static String getResult(@Nullable final Player player,
|
public static String getResult(@Nullable final Player player,
|
||||||
@NotNull final String identifier,
|
@NotNull final String identifier,
|
||||||
@Nullable final EcoPlugin plugin) {
|
@Nullable final EcoPlugin plugin) {
|
||||||
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
|
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
|
||||||
PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
|
Placeholder placeholder = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
|
||||||
|
|
||||||
if (entry == null && plugin != null) {
|
if (placeholder == null && plugin != null) {
|
||||||
PlaceholderEntry alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
|
Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
|
||||||
.get(identifier.toLowerCase());
|
.get(identifier.toLowerCase());
|
||||||
if (alternate != null) {
|
if (alternate != null) {
|
||||||
entry = alternate;
|
placeholder = alternate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry == null) {
|
if (placeholder == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player == null && entry.requiresPlayer()) {
|
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||||
|
if (player == null) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return PLACEHOLDER_CACHE.get(new EntryWithPlayer(playerPlaceholder, player));
|
||||||
|
}
|
||||||
|
} else if (placeholder instanceof PlayerlessPlaceholder playerlessPlaceholder) {
|
||||||
|
return playerlessPlaceholder.getValue();
|
||||||
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,10 +144,28 @@ public final class PlaceholderManager {
|
|||||||
*/
|
*/
|
||||||
public static String translatePlaceholders(@NotNull final String text,
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
@Nullable final Player player) {
|
@Nullable final Player player) {
|
||||||
|
return translatePlaceholders(text, player, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate all placeholders with respect to a player.
|
||||||
|
*
|
||||||
|
* @param text The text that may contain placeholders to translate.
|
||||||
|
* @param player The player to translate the placeholders with respect to.
|
||||||
|
* @param statics Extra static placeholders.
|
||||||
|
* @return The text, translated.
|
||||||
|
*/
|
||||||
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
|
@Nullable final Player player,
|
||||||
|
@NotNull final List<StaticPlaceholder> statics) {
|
||||||
String processed = text;
|
String processed = text;
|
||||||
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
|
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
|
||||||
processed = integration.translate(processed, player);
|
processed = integration.translate(processed, player);
|
||||||
}
|
}
|
||||||
|
for (StaticPlaceholder placeholder : statics) {
|
||||||
|
// Do I know this is a bad way of doing this? Yes.
|
||||||
|
processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue());
|
||||||
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,8 +184,8 @@ public final class PlaceholderManager {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static record EntryWithPlayer(@NotNull PlaceholderEntry entry,
|
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,
|
||||||
@Nullable Player player) {
|
@NotNull Player player) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
|||||||
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
|
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
|
||||||
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
|
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
|
||||||
import com.willfp.eco.core.recipe.parts.TestableStack;
|
import com.willfp.eco.core.recipe.parts.TestableStack;
|
||||||
|
import com.willfp.eco.core.recipe.parts.UnrestrictedMaterialTestableItem;
|
||||||
import com.willfp.eco.util.NamespacedKeyUtils;
|
import com.willfp.eco.util.NamespacedKeyUtils;
|
||||||
import com.willfp.eco.util.NumberUtils;
|
import com.willfp.eco.util.NumberUtils;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -42,9 +43,13 @@ public final class Items {
|
|||||||
* Cached custom item lookups, using {@link HashedItem}.
|
* Cached custom item lookups, using {@link HashedItem}.
|
||||||
*/
|
*/
|
||||||
private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
|
private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
|
||||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||||
.build(
|
.build(
|
||||||
key -> {
|
key -> {
|
||||||
|
if (!key.getItem().hasItemMeta()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
TestableItem match = null;
|
TestableItem match = null;
|
||||||
for (TestableItem item : REGISTRY.values()) {
|
for (TestableItem item : REGISTRY.values()) {
|
||||||
if (item.matches(key.getItem())) {
|
if (item.matches(key.getItem())) {
|
||||||
@@ -151,11 +156,16 @@ public final class Items {
|
|||||||
String[] split = args[0].toLowerCase().split(":");
|
String[] split = args[0].toLowerCase().split(":");
|
||||||
|
|
||||||
if (split.length == 1) {
|
if (split.length == 1) {
|
||||||
Material material = Material.getMaterial(args[0].toUpperCase());
|
String itemType = args[0];
|
||||||
|
boolean isWildcard = itemType.startsWith("*");
|
||||||
|
if (isWildcard) {
|
||||||
|
itemType = itemType.substring(1);
|
||||||
|
}
|
||||||
|
Material material = Material.getMaterial(itemType.toUpperCase());
|
||||||
if (material == null || material == Material.AIR) {
|
if (material == null || material == Material.AIR) {
|
||||||
return new EmptyTestableItem();
|
return new EmptyTestableItem();
|
||||||
}
|
}
|
||||||
item = new MaterialTestableItem(material);
|
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (split.length == 2) {
|
if (split.length == 2) {
|
||||||
@@ -179,11 +189,16 @@ public final class Items {
|
|||||||
This has been superseded by id amount
|
This has been superseded by id amount
|
||||||
*/
|
*/
|
||||||
if (part == null) {
|
if (part == null) {
|
||||||
Material material = Material.getMaterial(split[0].toUpperCase());
|
String itemType = split[0];
|
||||||
|
boolean isWildcard = itemType.startsWith("*");
|
||||||
|
if (isWildcard) {
|
||||||
|
itemType = itemType.substring(1);
|
||||||
|
}
|
||||||
|
Material material = Material.getMaterial(itemType.toUpperCase());
|
||||||
if (material == null || material == Material.AIR) {
|
if (material == null || material == Material.AIR) {
|
||||||
return new EmptyTestableItem();
|
return new EmptyTestableItem();
|
||||||
}
|
}
|
||||||
item = new MaterialTestableItem(material);
|
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
|
||||||
stackAmount = Integer.parseInt(split[1]);
|
stackAmount = Integer.parseInt(split[1]);
|
||||||
} else {
|
} else {
|
||||||
item = part;
|
item = part;
|
||||||
@@ -294,7 +309,7 @@ public final class Items {
|
|||||||
* @param itemStack The itemStack to check.
|
* @param itemStack The itemStack to check.
|
||||||
* @return If is recipe.
|
* @return If is recipe.
|
||||||
*/
|
*/
|
||||||
public static boolean isCustomItem(@NotNull final ItemStack itemStack) {
|
public static boolean isCustomItem(@Nullable final ItemStack itemStack) {
|
||||||
return getCustomItem(itemStack) != null;
|
return getCustomItem(itemStack) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +320,11 @@ public final class Items {
|
|||||||
* @return The custom item, or null if not exists.
|
* @return The custom item, or null if not exists.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) {
|
public static CustomItem getCustomItem(@Nullable final ItemStack itemStack) {
|
||||||
|
if (itemStack == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
|
return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public interface LookupHandler<T extends Testable<?>> {
|
|||||||
* <p>
|
* <p>
|
||||||
* You shouldn't override this method unless you're doing something
|
* You shouldn't override this method unless you're doing something
|
||||||
* technically interesting or weird. This is the entry point for all
|
* technically interesting or weird. This is the entry point for all
|
||||||
* lookup parsers, {@link this#parse(String[])} is to specify implementation-specific
|
* lookup parsers, parse() is to specify implementation-specific
|
||||||
* parsing.
|
* parsing.
|
||||||
*
|
*
|
||||||
* @param key The key.
|
* @param key The key.
|
||||||
@@ -56,7 +56,7 @@ public interface LookupHandler<T extends Testable<?>> {
|
|||||||
/**
|
/**
|
||||||
* Get the failsafe object.
|
* Get the failsafe object.
|
||||||
* <p>
|
* <p>
|
||||||
* A failsafe object should never pass {@link this#validate(Testable)}, as this will
|
* A failsafe object should never pass validate(), as this will
|
||||||
* cause issues with segment parsers. See {@link com.willfp.eco.core.items.ItemsLookupHandler} and
|
* cause issues with segment parsers. See {@link com.willfp.eco.core.items.ItemsLookupHandler} and
|
||||||
* {@link com.willfp.eco.core.recipe.parts.EmptyTestableItem} for examples.
|
* {@link com.willfp.eco.core.recipe.parts.EmptyTestableItem} for examples.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package com.willfp.eco.core.lookup;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for testing if any object matches another object.
|
* Interface for testing if any object matches another object.
|
||||||
*
|
*
|
||||||
* @param <T> The type of object.
|
* @param <T> The type of object.
|
||||||
*/
|
*/
|
||||||
public interface Testable<T> {
|
public interface Testable<T> extends Predicate<T> {
|
||||||
/**
|
/**
|
||||||
* If object matches the test.
|
* If object matches the test.
|
||||||
*
|
*
|
||||||
@@ -15,4 +17,9 @@ public interface Testable<T> {
|
|||||||
* @return If matches.
|
* @return If matches.
|
||||||
*/
|
*/
|
||||||
boolean matches(@Nullable T other);
|
boolean matches(@Nullable T other);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean test(@Nullable T other) {
|
||||||
|
return this.matches(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder represents a string that can hold a value.
|
||||||
|
*/
|
||||||
|
public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder, StaticPlaceholder {
|
||||||
|
/**
|
||||||
|
* Get the plugin that holds the placeholder.
|
||||||
|
*
|
||||||
|
* @return The plugin.
|
||||||
|
*/
|
||||||
|
EcoPlugin getPlugin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the identifier for the placeholder.
|
||||||
|
*
|
||||||
|
* @return The identifier.
|
||||||
|
*/
|
||||||
|
String getIdentifier();
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a class that can have placeholders injected into it.
|
||||||
|
*/
|
||||||
|
public interface PlaceholderInjectable {
|
||||||
|
/**
|
||||||
|
* Inject placeholder.
|
||||||
|
*
|
||||||
|
* @param placeholders The placeholders.
|
||||||
|
*/
|
||||||
|
default void injectPlaceholders(@NotNull StaticPlaceholder... placeholders) {
|
||||||
|
this.injectPlaceholders(List.of(placeholders));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject placeholder.
|
||||||
|
*
|
||||||
|
* @param placeholders The placeholders.
|
||||||
|
*/
|
||||||
|
void injectPlaceholders(@NotNull Iterable<StaticPlaceholder> placeholders);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear injected placeholders.
|
||||||
|
*/
|
||||||
|
void clearInjectedPlaceholders();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get injected placeholders.
|
||||||
|
*
|
||||||
|
* @return Injected placeholders.
|
||||||
|
*/
|
||||||
|
List<StaticPlaceholder> getInjectedPlaceholders();
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder that requires a player.
|
||||||
|
*/
|
||||||
|
public final class PlayerPlaceholder implements Placeholder {
|
||||||
|
/**
|
||||||
|
* The name of the placeholder.
|
||||||
|
*/
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to retrieve the output of the placeholder given a player.
|
||||||
|
*/
|
||||||
|
private final Function<Player, String> function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin for the placeholder.
|
||||||
|
*/
|
||||||
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new player placeholder.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin.
|
||||||
|
* @param identifier The identifier.
|
||||||
|
* @param function The function to retrieve the value.
|
||||||
|
*/
|
||||||
|
public PlayerPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
|
@NotNull final String identifier,
|
||||||
|
@NotNull final Function<Player, String> function) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the placeholder for a given player.
|
||||||
|
*
|
||||||
|
* @param player The player.
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
public String getValue(@NotNull final Player player) {
|
||||||
|
return function.apply(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the placeholder.
|
||||||
|
*
|
||||||
|
* @return The placeholder.
|
||||||
|
*/
|
||||||
|
public PlayerPlaceholder register() {
|
||||||
|
PlaceholderManager.registerPlaceholder(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EcoPlugin getPlugin() {
|
||||||
|
return this.plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return this.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof StaticPlaceholder that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
||||||
|
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder that does not require a player.
|
||||||
|
*/
|
||||||
|
public final class PlayerlessPlaceholder implements Placeholder {
|
||||||
|
/**
|
||||||
|
* The name of the placeholder.
|
||||||
|
*/
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to retrieve the output of the placeholder.
|
||||||
|
*/
|
||||||
|
private final Supplier<String> function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin for the placeholder.
|
||||||
|
*/
|
||||||
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new player placeholder.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin.
|
||||||
|
* @param identifier The identifier.
|
||||||
|
* @param function The function to retrieve the value.
|
||||||
|
*/
|
||||||
|
public PlayerlessPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
|
@NotNull final String identifier,
|
||||||
|
@NotNull final Supplier<String> function) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the placeholder.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return function.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the placeholder.
|
||||||
|
*
|
||||||
|
* @return The placeholder.
|
||||||
|
*/
|
||||||
|
public PlayerlessPlaceholder register() {
|
||||||
|
PlaceholderManager.registerPlaceholder(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EcoPlugin getPlugin() {
|
||||||
|
return this.plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return this.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof StaticPlaceholder that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
||||||
|
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.Eco;
|
||||||
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder that cannot be registered, and exists purely in injection.
|
||||||
|
*/
|
||||||
|
public final class StaticPlaceholder implements Placeholder {
|
||||||
|
/**
|
||||||
|
* The name of the placeholder.
|
||||||
|
*/
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to retrieve the output of the placeholder.
|
||||||
|
*/
|
||||||
|
private final Supplier<String> function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new player placeholder.
|
||||||
|
*
|
||||||
|
* @param identifier The identifier.
|
||||||
|
* @param function The function to retrieve the value.
|
||||||
|
*/
|
||||||
|
public StaticPlaceholder(@NotNull final String identifier,
|
||||||
|
@NotNull final Supplier<String> function) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the placeholder.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return function.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EcoPlugin getPlugin() {
|
||||||
|
return Eco.getHandler().getEcoPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return this.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof StaticPlaceholder that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(this.getIdentifier(), that.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.getIdentifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,8 @@ public final class ProxyConstants {
|
|||||||
*/
|
*/
|
||||||
public static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
|
public static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
|
||||||
"v1_17_R1",
|
"v1_17_R1",
|
||||||
"v1_18_R1"
|
"v1_18_R1",
|
||||||
|
"v1_18_R2"
|
||||||
);
|
);
|
||||||
|
|
||||||
private ProxyConstants() {
|
private ProxyConstants() {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public final class Recipes {
|
|||||||
* Cached recipes from matrix.
|
* Cached recipes from matrix.
|
||||||
*/
|
*/
|
||||||
private static final LoadingCache<ItemStack[], Optional<CraftingRecipe>> RECIPES_FROM_MATRIX = Caffeine.newBuilder()
|
private static final LoadingCache<ItemStack[], Optional<CraftingRecipe>> RECIPES_FROM_MATRIX = Caffeine.newBuilder()
|
||||||
|
.maximumSize(2048L)
|
||||||
.build(
|
.build(
|
||||||
matrix -> RECIPES.values().stream().filter(recipe -> recipe.test(matrix)).findFirst()
|
matrix -> RECIPES.values().stream().filter(recipe -> recipe.test(matrix)).findFirst()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -57,6 +57,23 @@ public class GroupedTestableItems implements TestableItem {
|
|||||||
throw new IllegalStateException("Empty group of children!");
|
throw new IllegalStateException("Empty group of children!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get matching child for an ItemStack.
|
||||||
|
*
|
||||||
|
* @param itemStack The ItemStack.
|
||||||
|
* @return The matching child, or null if the item matches nothing.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public TestableItem getMatchingChild(@NotNull final ItemStack itemStack) {
|
||||||
|
for (TestableItem child : children) {
|
||||||
|
if (child.matches(itemStack)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the children.
|
* Get the children.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.willfp.eco.core.recipe.parts;
|
package com.willfp.eco.core.recipe.parts;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.items.Items;
|
||||||
import com.willfp.eco.core.items.TestableItem;
|
import com.willfp.eco.core.items.TestableItem;
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -35,7 +36,13 @@ public class MaterialTestableItem implements TestableItem {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(@Nullable final ItemStack itemStack) {
|
public boolean matches(@Nullable final ItemStack itemStack) {
|
||||||
return itemStack != null && itemStack.getType() == material;
|
boolean simpleMatches = itemStack != null && itemStack.getType() == material;
|
||||||
|
|
||||||
|
if (!simpleMatches) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Items.isCustomItem(itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.willfp.eco.core.recipe.parts;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as material testable items, but doesn't filter out custom items.
|
||||||
|
*/
|
||||||
|
public class UnrestrictedMaterialTestableItem extends MaterialTestableItem {
|
||||||
|
/**
|
||||||
|
* Create a new simple recipe part.
|
||||||
|
*
|
||||||
|
* @param material The material.
|
||||||
|
*/
|
||||||
|
public UnrestrictedMaterialTestableItem(@NotNull final Material material) {
|
||||||
|
super(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the item matches the material.
|
||||||
|
*
|
||||||
|
* @param itemStack The item to test.
|
||||||
|
* @return If the item is of the specified material.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean matches(@Nullable final ItemStack itemStack) {
|
||||||
|
return itemStack != null && itemStack.getType() == this.getMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,11 +3,12 @@ package com.willfp.eco.core.recipe.recipes;
|
|||||||
import com.willfp.eco.core.Eco;
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
import com.willfp.eco.core.PluginDependent;
|
import com.willfp.eco.core.PluginDependent;
|
||||||
import com.willfp.eco.core.Prerequisite;
|
|
||||||
import com.willfp.eco.core.items.TestableItem;
|
import com.willfp.eco.core.items.TestableItem;
|
||||||
import com.willfp.eco.core.recipe.Recipes;
|
import com.willfp.eco.core.recipe.Recipes;
|
||||||
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
||||||
|
import com.willfp.eco.core.recipe.parts.GroupedTestableItems;
|
||||||
import com.willfp.eco.core.recipe.parts.TestableStack;
|
import com.willfp.eco.core.recipe.parts.TestableStack;
|
||||||
|
import com.willfp.eco.util.ListUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
@@ -66,9 +67,10 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean test(@NotNull final ItemStack[] matrix) {
|
public boolean test(@NotNull final ItemStack[] matrix) {
|
||||||
|
List<ItemStack> dynamicMatrix = Arrays.asList(matrix);
|
||||||
boolean matches = true;
|
boolean matches = true;
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
if (!parts.get(i).matches(matrix[i])) {
|
if (!parts.get(i).matches(ListUtils.getOrNull(dynamicMatrix, i))) {
|
||||||
matches = false;
|
matches = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,29 +104,38 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
|
|||||||
}
|
}
|
||||||
|
|
||||||
char character = String.valueOf(i).toCharArray()[0];
|
char character = String.valueOf(i).toCharArray()[0];
|
||||||
ItemStack item = parts.get(i).getItem();
|
|
||||||
|
|
||||||
if (parts.get(i) instanceof TestableStack) {
|
List<TestableItem> items = new ArrayList<>();
|
||||||
ItemMeta meta = item.getItemMeta();
|
if (parts.get(i) instanceof GroupedTestableItems group) {
|
||||||
assert meta != null;
|
items.addAll(group.getChildren());
|
||||||
|
} else {
|
||||||
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
items.add(parts.get(i));
|
||||||
assert lore != null;
|
|
||||||
lore.add("");
|
|
||||||
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
|
||||||
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
|
||||||
lore.add(add);
|
|
||||||
meta.setLore(lore);
|
|
||||||
item.setItemMeta(meta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(item));
|
List<ItemStack> displayedItems = new ArrayList<>();
|
||||||
}
|
|
||||||
|
|
||||||
if (Prerequisite.HAS_1_18.isMet() && !Prerequisite.HAS_PAPER.isMet()) {
|
for (TestableItem testableItem : items) {
|
||||||
if (Bukkit.getServer().getRecipe(this.getKey()) != null) {
|
if (testableItem instanceof TestableStack) {
|
||||||
return;
|
ItemStack item = testableItem.getItem().clone();
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
assert meta != null;
|
||||||
|
|
||||||
|
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||||
|
assert lore != null;
|
||||||
|
lore.add("");
|
||||||
|
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||||
|
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||||
|
lore.add(add);
|
||||||
|
meta.setLore(lore);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
|
||||||
|
displayedItems.add(item);
|
||||||
|
} else {
|
||||||
|
displayedItems.add(testableItem.getItem());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
Bukkit.getServer().addRecipe(shapedRecipe);
|
Bukkit.getServer().addRecipe(shapedRecipe);
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
package com.willfp.eco.core.recipe.recipes;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.willfp.eco.core.Eco;
|
||||||
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.PluginDependent;
|
||||||
|
import com.willfp.eco.core.items.TestableItem;
|
||||||
|
import com.willfp.eco.core.recipe.Recipes;
|
||||||
|
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
||||||
|
import com.willfp.eco.core.recipe.parts.GroupedTestableItems;
|
||||||
|
import com.willfp.eco.core.recipe.parts.TestableStack;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.RecipeChoice;
|
||||||
|
import org.bukkit.inventory.ShapelessRecipe;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shapeless crafting recipe.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> implements CraftingRecipe {
|
||||||
|
/**
|
||||||
|
* Recipe parts.
|
||||||
|
*/
|
||||||
|
private final List<TestableItem> parts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key of the recipe.
|
||||||
|
*/
|
||||||
|
private final NamespacedKey key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key of the displayed recipe.
|
||||||
|
*/
|
||||||
|
private final NamespacedKey displayedKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The recipe's output.
|
||||||
|
*/
|
||||||
|
private final ItemStack output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The permission.
|
||||||
|
*/
|
||||||
|
private final String permission;
|
||||||
|
|
||||||
|
private ShapelessCraftingRecipe(@NotNull final EcoPlugin plugin,
|
||||||
|
@NotNull final String key,
|
||||||
|
@NotNull final List<TestableItem> parts,
|
||||||
|
@NotNull final ItemStack output,
|
||||||
|
@Nullable final String permission) {
|
||||||
|
super(plugin);
|
||||||
|
|
||||||
|
this.parts = parts;
|
||||||
|
this.key = plugin.getNamespacedKeyFactory().create(key);
|
||||||
|
this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed");
|
||||||
|
this.output = output;
|
||||||
|
this.permission = permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a new test.
|
||||||
|
*
|
||||||
|
* @return The test.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public RecipeTest newTest() {
|
||||||
|
return new RecipeTest(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(@NotNull final ItemStack[] matrix) {
|
||||||
|
RecipeTest test = newTest();
|
||||||
|
|
||||||
|
for (ItemStack stack : matrix) {
|
||||||
|
if (test.matchAndRemove(stack) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register() {
|
||||||
|
Recipes.register(this);
|
||||||
|
|
||||||
|
Bukkit.getServer().removeRecipe(this.getKey());
|
||||||
|
Bukkit.getServer().removeRecipe(this.getDisplayedKey());
|
||||||
|
|
||||||
|
ShapelessRecipe shapelessRecipe = new ShapelessRecipe(this.getKey(), this.getOutput());
|
||||||
|
for (TestableItem part : parts) {
|
||||||
|
shapelessRecipe.addIngredient(part.getItem().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput());
|
||||||
|
for (TestableItem part : parts) {
|
||||||
|
List<TestableItem> items = new ArrayList<>();
|
||||||
|
if (part instanceof GroupedTestableItems group) {
|
||||||
|
items.addAll(group.getChildren());
|
||||||
|
} else {
|
||||||
|
items.add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> displayedItems = new ArrayList<>();
|
||||||
|
|
||||||
|
for (TestableItem testableItem : items) {
|
||||||
|
if (testableItem instanceof TestableStack) {
|
||||||
|
ItemStack item = testableItem.getItem().clone();
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
assert meta != null;
|
||||||
|
|
||||||
|
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||||
|
assert lore != null;
|
||||||
|
lore.add("");
|
||||||
|
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||||
|
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||||
|
lore.add(add);
|
||||||
|
meta.setLore(lore);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
|
||||||
|
displayedItems.add(item);
|
||||||
|
} else {
|
||||||
|
displayedItems.add(testableItem.getItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayedRecipe.addIngredient(new RecipeChoice.ExactChoice(displayedItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getServer().addRecipe(shapelessRecipe);
|
||||||
|
Bukkit.getServer().addRecipe(displayedRecipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new recipe builder.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin that owns the recipe.
|
||||||
|
* @param key The recipe key.
|
||||||
|
* @return A new builder.
|
||||||
|
*/
|
||||||
|
public static Builder builder(@NotNull final EcoPlugin plugin,
|
||||||
|
@NotNull final String key) {
|
||||||
|
return new Builder(plugin, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parts.
|
||||||
|
*
|
||||||
|
* @return The parts.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<TestableItem> getParts() {
|
||||||
|
return this.parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key.
|
||||||
|
*
|
||||||
|
* @return The key.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getKey() {
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the displayed key.
|
||||||
|
*
|
||||||
|
* @return The displayed key.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public NamespacedKey getDisplayedKey() {
|
||||||
|
return this.displayedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the output.
|
||||||
|
*
|
||||||
|
* @return The output.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ItemStack getOutput() {
|
||||||
|
return this.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the permission.
|
||||||
|
*
|
||||||
|
* @return The permission.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for recipes.
|
||||||
|
*/
|
||||||
|
public static final class Builder {
|
||||||
|
/**
|
||||||
|
* The recipe parts.
|
||||||
|
*/
|
||||||
|
private final List<TestableItem> recipeParts = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output of the recipe.
|
||||||
|
*/
|
||||||
|
private ItemStack output = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The permission for the recipe.
|
||||||
|
*/
|
||||||
|
private String permission = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key of the recipe.
|
||||||
|
*/
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin that created the recipe.
|
||||||
|
*/
|
||||||
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new recipe builder.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin that owns the recipe.
|
||||||
|
* @param key The recipe key.
|
||||||
|
*/
|
||||||
|
private Builder(@NotNull final EcoPlugin plugin,
|
||||||
|
@NotNull final String key) {
|
||||||
|
this.key = key;
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a recipe part.
|
||||||
|
*
|
||||||
|
* @param part The part of the recipe.
|
||||||
|
* @return The builder.
|
||||||
|
*/
|
||||||
|
public Builder addRecipePart(@NotNull final TestableItem part) {
|
||||||
|
recipeParts.add(part);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output of the recipe.
|
||||||
|
*
|
||||||
|
* @param output The output.
|
||||||
|
* @return The builder.
|
||||||
|
*/
|
||||||
|
public Builder setOutput(@NotNull final ItemStack output) {
|
||||||
|
this.output = output;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the permission required to craft the recipe.
|
||||||
|
*
|
||||||
|
* @param permission The permission.
|
||||||
|
* @return The builder.
|
||||||
|
*/
|
||||||
|
public Builder setPermission(@Nullable final String permission) {
|
||||||
|
this.permission = permission;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if recipe parts are all air.
|
||||||
|
*
|
||||||
|
* @return If recipe parts are all air.
|
||||||
|
*/
|
||||||
|
public boolean isAir() {
|
||||||
|
for (TestableItem recipePart : this.recipeParts) {
|
||||||
|
if (recipePart != null && !(recipePart instanceof EmptyTestableItem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the recipe.
|
||||||
|
*
|
||||||
|
* @return The built recipe.
|
||||||
|
*/
|
||||||
|
public ShapelessCraftingRecipe build() {
|
||||||
|
return new ShapelessCraftingRecipe(plugin, key.toLowerCase(), recipeParts, output, permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for shapeless recipes.
|
||||||
|
*/
|
||||||
|
public static final class RecipeTest {
|
||||||
|
/**
|
||||||
|
* The remaining items left to be found.
|
||||||
|
*/
|
||||||
|
private final List<TestableItem> remaining;
|
||||||
|
|
||||||
|
private RecipeTest(@NotNull final ShapelessCraftingRecipe recipe) {
|
||||||
|
this.remaining = new ArrayList<>(recipe.getParts());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the item is in the recipe, remove it from the remaining items to test and
|
||||||
|
* return the matching item.
|
||||||
|
*
|
||||||
|
* @param itemStack The item.
|
||||||
|
* @return The matching item, or null if no match was found.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public TestableItem matchAndRemove(@NotNull final ItemStack itemStack) {
|
||||||
|
if (remaining.isEmpty() && !(new EmptyTestableItem().matches(itemStack))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<TestableItem> match = remaining.stream()
|
||||||
|
.filter(item -> item.matches(itemStack))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
match.ifPresent(remaining::remove);
|
||||||
|
|
||||||
|
return match.orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A requirement is a defined goal that a player must meet.
|
|
||||||
*
|
|
||||||
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
|
|
||||||
*/
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.24.0", forRemoval = true)
|
|
||||||
public abstract class Requirement {
|
|
||||||
/**
|
|
||||||
* Create a new requirement.
|
|
||||||
*/
|
|
||||||
protected Requirement() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if the player meets the requirement.
|
|
||||||
*
|
|
||||||
* @param player The player.
|
|
||||||
* @param args The arguments.
|
|
||||||
* @return The requirement.
|
|
||||||
*/
|
|
||||||
public abstract boolean doesPlayerMeet(@NotNull Player player,
|
|
||||||
@NotNull List<String> args);
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains methods and fields pertaining to requirements.
|
|
||||||
*
|
|
||||||
* @deprecated See {@link Requirement}.
|
|
||||||
*/
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.24.0", forRemoval = true)
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
public final class Requirements {
|
|
||||||
/**
|
|
||||||
* Requires a player to have a permission.
|
|
||||||
*/
|
|
||||||
public static final Requirement HAS_PERMISSION = new com.willfp.eco.core.requirement.impl.RequirementHasPermission();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Placeholder equals value.
|
|
||||||
*/
|
|
||||||
public static final Requirement PLACEHOLDER_EQUALS = new com.willfp.eco.core.requirement.impl.RequirementPlaceholderEquals();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Numeric placeholder greater than value.
|
|
||||||
*/
|
|
||||||
public static final Requirement PLACEHOLDER_GREATER_THAN = new com.willfp.eco.core.requirement.impl.RequirementPlaceholderGreaterThan();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Numeric placeholder less than value.
|
|
||||||
*/
|
|
||||||
public static final Requirement PLACEHOLDER_LESS_THAN = new com.willfp.eco.core.requirement.impl.RequirementPlaceholderLessThan();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Requirements matching ID.
|
|
||||||
*
|
|
||||||
* @param name The ID to search for.
|
|
||||||
* @return The matching Requirements.
|
|
||||||
*/
|
|
||||||
public static Requirement getByID(@NotNull final String name) {
|
|
||||||
return switch (name.toLowerCase()) {
|
|
||||||
case "has-permission" -> HAS_PERMISSION;
|
|
||||||
case "placeholder-equals" -> PLACEHOLDER_EQUALS;
|
|
||||||
case "placeholder-greater-than" -> PLACEHOLDER_GREATER_THAN;
|
|
||||||
case "placeholder-less-than" -> PLACEHOLDER_LESS_THAN;
|
|
||||||
default -> new Requirement() {
|
|
||||||
@Override
|
|
||||||
public boolean doesPlayerMeet(@NotNull final Player player,
|
|
||||||
@NotNull final List<String> args) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Requirements() {
|
|
||||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement.impl;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moved to API in 6.26.0 after being marked for removal. This class should never be referenced, it
|
|
||||||
* was moved back to the API in order to remove backend components related to Requirements.
|
|
||||||
*
|
|
||||||
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.26.0", forRemoval = true)
|
|
||||||
public class RequirementHasPermission extends com.willfp.eco.core.requirement.Requirement {
|
|
||||||
@Override
|
|
||||||
public boolean doesPlayerMeet(@NotNull final Player player,
|
|
||||||
@NotNull final List<String> args) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return player.hasPermission(args.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement.impl;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moved to API in 6.26.0 after being marked for removal. This class should never be referenced, it
|
|
||||||
* was moved back to the API in order to remove backend components related to Requirements.
|
|
||||||
*
|
|
||||||
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.26.0", forRemoval = true)
|
|
||||||
public class RequirementPlaceholderEquals extends com.willfp.eco.core.requirement.Requirement {
|
|
||||||
@Override
|
|
||||||
public boolean doesPlayerMeet(@NotNull final Player player,
|
|
||||||
@NotNull final List<String> args) {
|
|
||||||
if (args.size() < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PlaceholderManager.translatePlaceholders(args.get(0), player).equalsIgnoreCase(args.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement.impl;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moved to API in 6.26.0 after being marked for removal. This class should never be referenced, it
|
|
||||||
* was moved back to the API in order to remove backend components related to Requirements.
|
|
||||||
*
|
|
||||||
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.26.0", forRemoval = true)
|
|
||||||
public class RequirementPlaceholderGreaterThan extends com.willfp.eco.core.requirement.Requirement {
|
|
||||||
@Override
|
|
||||||
public boolean doesPlayerMeet(@NotNull final Player player,
|
|
||||||
@NotNull final List<String> args) {
|
|
||||||
if (args.size() < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double actual;
|
|
||||||
try {
|
|
||||||
actual = Double.parseDouble(PlaceholderManager.translatePlaceholders(args.get(0), player));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double expected;
|
|
||||||
try {
|
|
||||||
expected = Double.parseDouble(args.get(1));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return actual >= expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package com.willfp.eco.core.requirement.impl;
|
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moved to API in 6.26.0 after being marked for removal. This class should never be referenced, it
|
|
||||||
* was moved back to the API in order to remove backend components related to Requirements.
|
|
||||||
*
|
|
||||||
* @deprecated No typing, weak definitions, and not an API component. Shouldn't be in eco.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.27.0")
|
|
||||||
@Deprecated(since = "6.26.0", forRemoval = true)
|
|
||||||
public class RequirementPlaceholderLessThan extends com.willfp.eco.core.requirement.Requirement {
|
|
||||||
@Override
|
|
||||||
public boolean doesPlayerMeet(@NotNull final Player player,
|
|
||||||
@NotNull final List<String> args) {
|
|
||||||
if (args.size() < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double actual;
|
|
||||||
try {
|
|
||||||
actual = Double.parseDouble(PlaceholderManager.translatePlaceholders(args.get(0), player));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double expected;
|
|
||||||
try {
|
|
||||||
expected = Double.parseDouble(args.get(1));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return actual < expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Eco.getHandler().getEcoPlugin().getLogger().severe("Loading for-removal Requirements system! This will throw an error once 6.27.0 is released."
|
|
||||||
+ "Make sure you're running the latest version of all your plugins!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.willfp.eco.core.serialization;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize objects from configs.
|
||||||
|
* <p>
|
||||||
|
* Deserializers should <b>never</b> throw errors due to invalid configs,
|
||||||
|
* all edge cases must be covered, and all failures must be encapsulated as null.
|
||||||
|
*
|
||||||
|
* @param <T> The type of object to deserialize.
|
||||||
|
*/
|
||||||
|
public interface ConfigDeserializer<T> {
|
||||||
|
/**
|
||||||
|
* Deserialize a config to an object.
|
||||||
|
*
|
||||||
|
* @param config The config.
|
||||||
|
* @return The object, or null if invalid.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
T deserialize(@NotNull Config config);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.willfp.eco.core.serialization;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.config.interfaces.Config;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize objects to configs.
|
||||||
|
*
|
||||||
|
* @param <T> The type of object to serialize.
|
||||||
|
*/
|
||||||
|
public interface ConfigSerializer<T> {
|
||||||
|
/**
|
||||||
|
* Serialize an object to a config.
|
||||||
|
*
|
||||||
|
* @param obj The object.
|
||||||
|
* @return The config.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Config serialize(@NotNull T obj);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.willfp.eco.core.serialization;
|
||||||
|
|
||||||
|
import org.bukkit.Keyed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializer with a key.
|
||||||
|
*
|
||||||
|
* @param <T> The type of object to deserialize.
|
||||||
|
* @see ConfigDeserializer
|
||||||
|
*/
|
||||||
|
public interface KeyedDeserializer<T> extends ConfigDeserializer<T>, Keyed {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.willfp.eco.core.serialization;
|
||||||
|
|
||||||
|
import org.bukkit.Keyed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializer with a key.
|
||||||
|
*
|
||||||
|
* @param <T> The type of object to serialize.
|
||||||
|
* @see ConfigSerializer
|
||||||
|
*/
|
||||||
|
public interface KeyedSerializer<T> extends ConfigSerializer<T>, Keyed {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.willfp.eco.util;
|
package com.willfp.eco.util;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -9,28 +8,16 @@ import org.bukkit.block.Block;
|
|||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities / API methods for blocks.
|
* Utilities / API methods for blocks.
|
||||||
*/
|
*/
|
||||||
public final class BlockUtils {
|
public final class BlockUtils {
|
||||||
/**
|
|
||||||
* If the meta set function has been set.
|
|
||||||
*/
|
|
||||||
private static boolean initialized = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The block break function.
|
|
||||||
*/
|
|
||||||
private static BiConsumer<Player, Block> blockBreakConsumer = null;
|
|
||||||
|
|
||||||
private static Set<Block> getNearbyBlocks(@NotNull final Block start,
|
private static Set<Block> getNearbyBlocks(@NotNull final Block start,
|
||||||
@NotNull final List<Material> allowedMaterials,
|
@NotNull final List<Material> allowedMaterials,
|
||||||
@NotNull final Set<Block> blocks,
|
@NotNull final Set<Block> blocks,
|
||||||
@@ -75,12 +62,11 @@ public final class BlockUtils {
|
|||||||
*
|
*
|
||||||
* @param player The player to break the block as.
|
* @param player The player to break the block as.
|
||||||
* @param block The block to break.
|
* @param block The block to break.
|
||||||
|
* @deprecated Added into spigot API in 1.17.1
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.26.2", forRemoval = true)
|
||||||
public static void breakBlock(@NotNull final Player player,
|
public static void breakBlock(@NotNull final Player player,
|
||||||
@NotNull final Block block) {
|
@NotNull final Block block) {
|
||||||
Validate.isTrue(initialized, "Must be initialized!");
|
|
||||||
Validate.notNull(blockBreakConsumer, "Must be initialized!");
|
|
||||||
|
|
||||||
Location location = block.getLocation();
|
Location location = block.getLocation();
|
||||||
World world = location.getWorld();
|
World world = location.getWorld();
|
||||||
assert world != null;
|
assert world != null;
|
||||||
@@ -89,7 +75,7 @@ public final class BlockUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockBreakConsumer.accept(player, block);
|
player.breakBlock(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,20 +93,6 @@ public final class BlockUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the block break function.
|
|
||||||
*
|
|
||||||
* @param function The function.
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public static void initialize(@NotNull final BiConsumer<Player, Block> function) {
|
|
||||||
Validate.isTrue(!initialized, "Already initialized!");
|
|
||||||
|
|
||||||
blockBreakConsumer = function;
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockUtils() {
|
private BlockUtils() {
|
||||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.willfp.eco.util;
|
package com.willfp.eco.util;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@@ -7,10 +8,10 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities / API methods for numbers.
|
* Utilities / API methods for numbers.
|
||||||
@@ -24,7 +25,7 @@ public final class NumberUtils {
|
|||||||
/**
|
/**
|
||||||
* Crunch handler.
|
* Crunch handler.
|
||||||
*/
|
*/
|
||||||
private static BiFunction<String, Player, Double> crunch = null;
|
private static CrunchHandler crunch = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of roman numerals to look up.
|
* Set of roman numerals to look up.
|
||||||
@@ -251,7 +252,21 @@ public final class NumberUtils {
|
|||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@Nullable final Player player) {
|
@Nullable final Player player) {
|
||||||
return crunch.apply(expression, player);
|
return evaluateExpression(expression, player, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate an expression with respect to a player (for placeholders).
|
||||||
|
*
|
||||||
|
* @param expression The expression.
|
||||||
|
* @param player The player.
|
||||||
|
* @param statics The static placeholders.
|
||||||
|
* @return The value of the expression, or zero if invalid.
|
||||||
|
*/
|
||||||
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
|
@Nullable final Player player,
|
||||||
|
@NotNull final Iterable<StaticPlaceholder> statics) {
|
||||||
|
return crunch.evaluate(expression, player, statics);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,11 +275,29 @@ public final class NumberUtils {
|
|||||||
* @param handler The handler.
|
* @param handler The handler.
|
||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public static void initCrunch(@NotNull final BiFunction<String, Player, Double> handler) {
|
public static void initCrunch(@NotNull final CrunchHandler handler) {
|
||||||
Validate.isTrue(crunch == null, "Already initialized!");
|
Validate.isTrue(crunch == null, "Already initialized!");
|
||||||
crunch = handler;
|
crunch = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridge component for crunch.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public interface CrunchHandler {
|
||||||
|
/**
|
||||||
|
* Evaluate an expression.
|
||||||
|
*
|
||||||
|
* @param expression The expression.
|
||||||
|
* @param player The player.
|
||||||
|
* @param statics The statics.
|
||||||
|
* @return The value of the expression, or zero if invalid.
|
||||||
|
*/
|
||||||
|
double evaluate(@NotNull String expression,
|
||||||
|
@Nullable Player player,
|
||||||
|
@NotNull Iterable<StaticPlaceholder> statics);
|
||||||
|
}
|
||||||
|
|
||||||
private NumberUtils() {
|
private NumberUtils() {
|
||||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
import com.willfp.eco.core.Prerequisite;
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.TextDecoration;
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
@@ -324,17 +323,16 @@ public final class StringUtils {
|
|||||||
|
|
||||||
private static String processFormatting(@NotNull final String message) {
|
private static String processFormatting(@NotNull final String message) {
|
||||||
String processedMessage = message;
|
String processedMessage = message;
|
||||||
|
// Run MiniMessage first so it doesn't complain
|
||||||
|
processedMessage = translateMiniMessage(processedMessage);
|
||||||
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
|
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
|
||||||
processedMessage = translateGradients(processedMessage);
|
processedMessage = translateGradients(processedMessage);
|
||||||
processedMessage = translateHexColorCodes(processedMessage);
|
processedMessage = translateHexColorCodes(processedMessage);
|
||||||
if (Prerequisite.HAS_PAPER.isMet()) {
|
|
||||||
processedMessage = translateMiniMessage(processedMessage);
|
|
||||||
}
|
|
||||||
return processedMessage;
|
return processedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String translateMiniMessage(@NotNull final String message) {
|
private static String translateMiniMessage(@NotNull final String message) {
|
||||||
return LEGACY_COMPONENT_SERIALIZER.serialize(MiniMessage.get().parse(message));
|
return Eco.getHandler().formatMiniMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String translateHexColorCodes(@NotNull final String message) {
|
private static String translateHexColorCodes(@NotNull final String message) {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@file:JvmName("EntityExtensions")
|
||||||
|
|
||||||
|
package com.willfp.eco.core.entities
|
||||||
|
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityController
|
||||||
|
import org.bukkit.entity.Mob
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see EntityController.getFor
|
||||||
|
*/
|
||||||
|
val <T : Mob> T.controller: EntityController<T>
|
||||||
|
get() = EntityController.getFor(this)
|
||||||
@@ -5,7 +5,7 @@ dependencies {
|
|||||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||||
compileOnly 'me.clip:placeholderapi:2.10.10'
|
compileOnly 'me.clip:placeholderapi:2.10.10'
|
||||||
compileOnly 'org.reflections:reflections:0.9.12'
|
compileOnly 'org.reflections:reflections:0.9.12'
|
||||||
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
|
compileOnly 'net.kyori:adventure-text-minimessage:4.10.0'
|
||||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
|
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
|
||||||
compileOnly 'org.objenesis:objenesis:3.2'
|
compileOnly 'org.objenesis:objenesis:3.2'
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
package com.willfp.eco.internal.config.json
|
package com.willfp.eco.internal.config.json
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class EcoJSONConfigSection(values: Map<String, Any?>) : EcoJSONConfigWrapper() {
|
class EcoJSONConfigSection(values: Map<String, Any?>, injections: Collection<StaticPlaceholder> = emptyList()) : EcoJSONConfigWrapper() {
|
||||||
init {
|
init {
|
||||||
init(values)
|
init(values)
|
||||||
|
this.injections = injections.toMutableList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.google.gson.Gson
|
|||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.willfp.eco.core.config.ConfigType
|
import com.willfp.eco.core.config.ConfigType
|
||||||
import com.willfp.eco.core.config.interfaces.JSONConfig
|
import com.willfp.eco.core.config.interfaces.JSONConfig
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||||
import com.willfp.eco.util.StringUtils
|
import com.willfp.eco.util.StringUtils
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -22,6 +23,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
val values = ConcurrentHashMap<String, Any?>()
|
val values = ConcurrentHashMap<String, Any?>()
|
||||||
|
|
||||||
private val cache = ConcurrentHashMap<String, Any>()
|
private val cache = ConcurrentHashMap<String, Any>()
|
||||||
|
var injections = mutableListOf<StaticPlaceholder>()
|
||||||
|
|
||||||
fun init(values: Map<String, Any?>) {
|
fun init(values: Map<String, Any?>) {
|
||||||
this.values.clear()
|
this.values.clear()
|
||||||
@@ -62,7 +64,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
}
|
}
|
||||||
return if (values[closestPath] is Map<*, *> && path != closestPath) {
|
return if (values[closestPath] is Map<*, *> && path != closestPath) {
|
||||||
val section =
|
val section =
|
||||||
EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!)
|
EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!, injections)
|
||||||
section.getOfKnownType(path.substring(closestPath.length + 1), clazz, false)
|
section.getOfKnownType(path.substring(closestPath.length + 1), clazz, false)
|
||||||
} else {
|
} else {
|
||||||
if (values.containsKey(closestPath)) {
|
if (values.containsKey(closestPath)) {
|
||||||
@@ -88,7 +90,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
for (key in values.keys) {
|
for (key in values.keys) {
|
||||||
list.add(root + key)
|
list.add(root + key)
|
||||||
if (values[key] is Map<*, *>) {
|
if (values[key] is Map<*, *>) {
|
||||||
val section = EcoJSONConfigSection((values[key] as Map<String, Any?>?)!!)
|
val section = EcoJSONConfigSection((values[key] as Map<String, Any?>?)!!, injections)
|
||||||
list.addAll(section.getDeepKeys(list, "$root$key."))
|
list.addAll(section.getDeepKeys(list, "$root$key."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +119,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
closestPath = split[0]
|
closestPath = split[0]
|
||||||
}
|
}
|
||||||
if (values[closestPath] is Map<*, *> && path != closestPath) {
|
if (values[closestPath] is Map<*, *> && path != closestPath) {
|
||||||
val section = EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!)
|
val section = EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!, injections)
|
||||||
section.setRecursively(path.substring(closestPath.length + 1), obj)
|
section.setRecursively(path.substring(closestPath.length + 1), obj)
|
||||||
values[closestPath] = section.values
|
values[closestPath] = section.values
|
||||||
} else {
|
} else {
|
||||||
@@ -130,13 +132,13 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getSubsection(path: String): JSONConfig {
|
override fun getSubsection(path: String): JSONConfig {
|
||||||
return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf())
|
return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf(), injections)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSubsectionOrNull(path: String): JSONConfig? {
|
override fun getSubsectionOrNull(path: String): JSONConfig? {
|
||||||
return if (values.containsKey(path)) {
|
return if (values.containsKey(path)) {
|
||||||
val subsection = values[path] as Map<String, Any>
|
val subsection = values[path] as Map<String, Any>
|
||||||
EcoJSONConfigSection(subsection)
|
EcoJSONConfigSection(subsection, injections)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -147,7 +149,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
?: return null
|
?: return null
|
||||||
val configs = mutableListOf<JSONConfig>()
|
val configs = mutableListOf<JSONConfig>()
|
||||||
for (map in maps) {
|
for (map in maps) {
|
||||||
configs.add(EcoJSONConfigSection(map))
|
configs.add(EcoJSONConfigSection(map, injections))
|
||||||
}
|
}
|
||||||
return configs.toMutableList()
|
return configs.toMutableList()
|
||||||
}
|
}
|
||||||
@@ -206,11 +208,26 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
|||||||
return (getOfKnownType(path, Any::class.java) as Collection<Double>?)?.toMutableList()
|
return (getOfKnownType(path, Any::class.java) as Collection<Double>?)?.toMutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun injectPlaceholders(placeholders: Iterable<StaticPlaceholder>) {
|
||||||
|
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
|
||||||
|
injections.addAll(placeholders)
|
||||||
|
this.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
|
||||||
|
return injections.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearInjectedPlaceholders() {
|
||||||
|
injections.clear()
|
||||||
|
this.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getType(): ConfigType {
|
override fun getType(): ConfigType {
|
||||||
return ConfigType.JSON
|
return ConfigType.JSON
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clone(): JSONConfig {
|
override fun clone(): JSONConfig {
|
||||||
return EcoJSONConfigSection(this.values.toMutableMap())
|
return EcoJSONConfigSection(this.values.toMutableMap(), injections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.willfp.eco.internal.config.yaml
|
package com.willfp.eco.internal.config.yaml
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||||
import org.bukkit.configuration.ConfigurationSection
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
|
|
||||||
class EcoYamlConfigSection(section: ConfigurationSection) : EcoYamlConfigWrapper<ConfigurationSection>() {
|
class EcoYamlConfigSection(section: ConfigurationSection, injections: Collection<StaticPlaceholder> = emptyList()) : EcoYamlConfigWrapper<ConfigurationSection>() {
|
||||||
init {
|
init {
|
||||||
init(section)
|
init(section)
|
||||||
|
this.injections = injections.toMutableList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.willfp.eco.internal.config.yaml
|
|||||||
|
|
||||||
import com.willfp.eco.core.config.ConfigType
|
import com.willfp.eco.core.config.ConfigType
|
||||||
import com.willfp.eco.core.config.interfaces.Config
|
import com.willfp.eco.core.config.interfaces.Config
|
||||||
|
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||||
import com.willfp.eco.util.StringUtils
|
import com.willfp.eco.util.StringUtils
|
||||||
import org.bukkit.configuration.ConfigurationSection
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
import org.bukkit.configuration.file.YamlConfiguration
|
import org.bukkit.configuration.file.YamlConfiguration
|
||||||
@@ -11,6 +12,7 @@ import java.io.StringReader
|
|||||||
open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||||
lateinit var handle: T
|
lateinit var handle: T
|
||||||
private val cache = mutableMapOf<String, Any?>()
|
private val cache = mutableMapOf<String, Any?>()
|
||||||
|
var injections = mutableListOf<StaticPlaceholder>()
|
||||||
|
|
||||||
protected fun init(config: T): Config {
|
protected fun init(config: T): Config {
|
||||||
handle = config
|
handle = config
|
||||||
@@ -57,7 +59,7 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
|||||||
if (raw == null) {
|
if (raw == null) {
|
||||||
cache[path] = null
|
cache[path] = null
|
||||||
} else {
|
} else {
|
||||||
cache[path] = EcoYamlConfigSection(raw)
|
cache[path] = EcoYamlConfigSection(raw, injections)
|
||||||
}
|
}
|
||||||
getSubsectionOrNull(path)
|
getSubsectionOrNull(path)
|
||||||
}
|
}
|
||||||
@@ -214,7 +216,7 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
|||||||
for (map in mapList) {
|
for (map in mapList) {
|
||||||
val temp = YamlConfiguration.loadConfiguration(StringReader(""))
|
val temp = YamlConfiguration.loadConfiguration(StringReader(""))
|
||||||
temp.createSection("a", map)
|
temp.createSection("a", map)
|
||||||
configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!))
|
configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!, injections))
|
||||||
}
|
}
|
||||||
|
|
||||||
cache[path] = if (has(path)) configList else emptyList()
|
cache[path] = if (has(path)) configList else emptyList()
|
||||||
@@ -225,6 +227,21 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun injectPlaceholders(placeholders: Iterable<StaticPlaceholder>) {
|
||||||
|
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
|
||||||
|
injections.addAll(placeholders)
|
||||||
|
this.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
|
||||||
|
return injections.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearInjectedPlaceholders() {
|
||||||
|
injections.clear()
|
||||||
|
this.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getType(): ConfigType {
|
override fun getType(): ConfigType {
|
||||||
return ConfigType.JSON
|
return ConfigType.JSON
|
||||||
}
|
}
|
||||||
@@ -235,7 +252,8 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
|||||||
StringReader(
|
StringReader(
|
||||||
toPlaintext()
|
toPlaintext()
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
|
injections
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.willfp.eco.internal.fast
|
|
||||||
|
|
||||||
import com.willfp.eco.core.fast.FastItemStack
|
|
||||||
import org.bukkit.inventory.ItemFlag
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
abstract class EcoFastItemStack<T: Any>(
|
|
||||||
val handle: T,
|
|
||||||
val bukkit: ItemStack
|
|
||||||
) : FastItemStack {
|
|
||||||
override fun unwrap(): ItemStack {
|
|
||||||
return bukkit
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getBitModifier(hideFlag: ItemFlag): Int {
|
|
||||||
return 1 shl hideFlag.ordinal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ class EcoMenu(
|
|||||||
val slots: List<MutableList<EcoSlot>>,
|
val slots: List<MutableList<EcoSlot>>,
|
||||||
private val title: String,
|
private val title: String,
|
||||||
private val onClose: CloseHandler
|
private val onClose: CloseHandler
|
||||||
): Menu {
|
) : Menu {
|
||||||
override fun getSlot(row: Int, column: Int): Slot {
|
override fun getSlot(row: Int, column: Int): Slot {
|
||||||
if (row < 1 || row > this.rows) {
|
if (row < 1 || row > this.rows) {
|
||||||
return slots[0][0]
|
return slots[0][0]
|
||||||
@@ -46,7 +46,7 @@ class EcoMenu(
|
|||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
val lore = meta.lore
|
val lore = meta.lore
|
||||||
if (lore != null) {
|
if (lore != null) {
|
||||||
lore.replaceAll{ s -> StringUtils.format(s, player) }
|
lore.replaceAll { s -> StringUtils.format(s, player) }
|
||||||
meta.lore = lore
|
meta.lore = lore
|
||||||
}
|
}
|
||||||
slotItem.itemMeta = meta
|
slotItem.itemMeta = meta
|
||||||
@@ -103,4 +103,9 @@ class EcoMenu(
|
|||||||
inventory ?: return HashSet()
|
inventory ?: return HashSet()
|
||||||
return inventory.data.keys
|
return inventory.data.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun refresh(player: Player) {
|
||||||
|
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory) ?: return
|
||||||
|
inventory.refresh(player)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user