Compare commits
134 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -88,7 +88,7 @@ Maven:
|
||||
</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:
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ dependencies {
|
||||
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_18_R1", configuration = "reobf"))
|
||||
implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -92,12 +93,12 @@ allprojects {
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||
|
||||
// Adventure
|
||||
compileOnly("net.kyori:adventure-api:4.9.3")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
|
||||
compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3")
|
||||
compileOnly("net.kyori:adventure-api:4.10.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.10.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-legacy:4.10.0")
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ allprojects {
|
||||
exclude(group = "org.spongepowered", module = "configurate-hocon")
|
||||
exclude(group = "com.darkblade12", module = "particleeffect")
|
||||
exclude(group = "com.github.cryptomorin", module = "XSeries")
|
||||
exclude(group = "net.wesjd", module = "anvilgui")
|
||||
}
|
||||
|
||||
configurations.testImplementation {
|
||||
@@ -129,8 +131,8 @@ allprojects {
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate("org.bstats", "com.willfp.eco.shaded.bstats")
|
||||
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")
|
||||
relocate("org.bstats", "com.willfp.eco.libs.bstats")
|
||||
relocate("redempt.crunch", "com.willfp.eco.libs.crunch")
|
||||
}
|
||||
|
||||
compileJava {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
dependencies {
|
||||
// Adventure
|
||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
|
||||
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
|
||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
|
||||
|
||||
// Other
|
||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||
@@ -13,6 +12,10 @@ dependencies {
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
build.dependsOn publishToMavenLocal
|
||||
|
||||
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.keys.KeyRegistry;
|
||||
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.extensions.ExtensionLoader;
|
||||
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.NamespacedKey;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Mob;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -32,7 +34,6 @@ import java.util.logging.Logger;
|
||||
* @see Eco#getHandler()
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@SuppressWarnings("removal")
|
||||
public interface Handler {
|
||||
/**
|
||||
* Create a scheduler.
|
||||
@@ -262,4 +263,23 @@ public interface Handler {
|
||||
@NotNull
|
||||
PluginProps getProps(@Nullable PluginProps existing,
|
||||
@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.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.StringUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -9,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -18,7 +21,7 @@ import java.util.Objects;
|
||||
* Contains all methods that must exist in yaml and json configurations.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface Config extends Cloneable {
|
||||
public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
/**
|
||||
* Clears cache.
|
||||
*/
|
||||
@@ -563,7 +566,7 @@ public interface Config extends Cloneable {
|
||||
*/
|
||||
default double getDoubleFromExpression(@NotNull String path,
|
||||
@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.
|
||||
*/
|
||||
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.interfaces.Config;
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -134,6 +135,26 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.willfp.eco.core.integrations.placeholder;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
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.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -10,10 +14,13 @@ import java.util.Objects;
|
||||
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>
|
||||
* It should be fairly straightforward.
|
||||
*
|
||||
* @deprecated Confusing functionality with inconsistent nullability and poor naming.
|
||||
*/
|
||||
@Deprecated(since = "6.28.0", forRemoval = true)
|
||||
public class PlaceholderEntry {
|
||||
/**
|
||||
* The name of the placeholder, used in lookups.
|
||||
@@ -140,7 +147,28 @@ public class PlaceholderEntry {
|
||||
* Register the placeholder.
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -4,11 +4,16 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.willfp.eco.core.Eco;
|
||||
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.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -19,11 +24,12 @@ import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
* Class to handle placeholder integrations.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public final class PlaceholderManager {
|
||||
/**
|
||||
* 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.
|
||||
@@ -35,7 +41,7 @@ public final class PlaceholderManager {
|
||||
*/
|
||||
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(key -> key.entry.getResult(key.player));
|
||||
.build(key -> key.entry.getValue(key.player));
|
||||
|
||||
/**
|
||||
* Register a new placeholder integration.
|
||||
@@ -50,16 +56,31 @@ public final class PlaceholderManager {
|
||||
/**
|
||||
* 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) {
|
||||
EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
|
||||
Map<String, PlaceholderEntry> pluginPlaceholders = REGISTERED_PLACEHOLDERS
|
||||
public static void registerPlaceholder(@NotNull final Placeholder placeholder) {
|
||||
if (placeholder instanceof StaticPlaceholder) {
|
||||
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<>());
|
||||
pluginPlaceholders.put(expansion.getIdentifier(), expansion);
|
||||
pluginPlaceholders.put(placeholder.getIdentifier(), placeholder);
|
||||
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.
|
||||
*
|
||||
@@ -82,29 +103,36 @@ public final class PlaceholderManager {
|
||||
* @param plugin The plugin for the placeholder.
|
||||
* @return The value of the placeholder.
|
||||
*/
|
||||
@NotNull
|
||||
public static String getResult(@Nullable final Player player,
|
||||
@NotNull final String identifier,
|
||||
@Nullable final EcoPlugin 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) {
|
||||
PlaceholderEntry alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
|
||||
if (placeholder == null && plugin != null) {
|
||||
Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
|
||||
.get(identifier.toLowerCase());
|
||||
if (alternate != null) {
|
||||
entry = alternate;
|
||||
placeholder = alternate;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == null) {
|
||||
if (placeholder == null) {
|
||||
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 PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,10 +144,28 @@ public final class PlaceholderManager {
|
||||
*/
|
||||
public static String translatePlaceholders(@NotNull final String text,
|
||||
@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;
|
||||
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -138,8 +184,8 @@ public final class PlaceholderManager {
|
||||
return found;
|
||||
}
|
||||
|
||||
private static record EntryWithPlayer(@NotNull PlaceholderEntry entry,
|
||||
@Nullable Player player) {
|
||||
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,
|
||||
@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.ModifiedTestableItem;
|
||||
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.NumberUtils;
|
||||
import org.bukkit.Material;
|
||||
@@ -42,9 +43,13 @@ public final class Items {
|
||||
* Cached custom item lookups, using {@link HashedItem}.
|
||||
*/
|
||||
private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
|
||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(
|
||||
key -> {
|
||||
if (!key.getItem().hasItemMeta()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
TestableItem match = null;
|
||||
for (TestableItem item : REGISTRY.values()) {
|
||||
if (item.matches(key.getItem())) {
|
||||
@@ -151,11 +156,16 @@ public final class Items {
|
||||
String[] split = args[0].toLowerCase().split(":");
|
||||
|
||||
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) {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
item = new MaterialTestableItem(material);
|
||||
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
|
||||
}
|
||||
|
||||
if (split.length == 2) {
|
||||
@@ -179,11 +189,16 @@ public final class Items {
|
||||
This has been superseded by id amount
|
||||
*/
|
||||
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) {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
item = new MaterialTestableItem(material);
|
||||
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
|
||||
stackAmount = Integer.parseInt(split[1]);
|
||||
} else {
|
||||
item = part;
|
||||
@@ -294,7 +309,7 @@ public final class Items {
|
||||
* @param itemStack The itemStack to check.
|
||||
* @return If is recipe.
|
||||
*/
|
||||
public static boolean isCustomItem(@NotNull final ItemStack itemStack) {
|
||||
public static boolean isCustomItem(@Nullable final ItemStack itemStack) {
|
||||
return getCustomItem(itemStack) != null;
|
||||
}
|
||||
|
||||
@@ -305,7 +320,11 @@ public final class Items {
|
||||
* @return The custom item, or null if not exists.
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public interface LookupHandler<T extends Testable<?>> {
|
||||
* <p>
|
||||
* You shouldn't override this method unless you're doing something
|
||||
* 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.
|
||||
*
|
||||
* @param key The key.
|
||||
@@ -56,7 +56,7 @@ public interface LookupHandler<T extends Testable<?>> {
|
||||
/**
|
||||
* Get the failsafe object.
|
||||
* <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
|
||||
* {@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 java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Interface for testing if any object matches another object.
|
||||
*
|
||||
* @param <T> The type of object.
|
||||
*/
|
||||
public interface Testable<T> {
|
||||
public interface Testable<T> extends Predicate<T> {
|
||||
/**
|
||||
* If object matches the test.
|
||||
*
|
||||
@@ -15,4 +17,9 @@ public interface Testable<T> {
|
||||
* @return If matches.
|
||||
*/
|
||||
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(
|
||||
"v1_17_R1",
|
||||
"v1_18_R1"
|
||||
"v1_18_R1",
|
||||
"v1_18_R2"
|
||||
);
|
||||
|
||||
private ProxyConstants() {
|
||||
|
||||
@@ -31,6 +31,7 @@ public final class Recipes {
|
||||
* Cached recipes from matrix.
|
||||
*/
|
||||
private static final LoadingCache<ItemStack[], Optional<CraftingRecipe>> RECIPES_FROM_MATRIX = Caffeine.newBuilder()
|
||||
.maximumSize(2048L)
|
||||
.build(
|
||||
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!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.recipe.parts;
|
||||
|
||||
import com.willfp.eco.core.items.Items;
|
||||
import com.willfp.eco.core.items.TestableItem;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
@@ -35,7 +36,13 @@ public class MaterialTestableItem implements TestableItem {
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
|
||||
@@ -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.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.eco.core.Prerequisite;
|
||||
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 com.willfp.eco.util.ListUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -66,9 +67,10 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
|
||||
|
||||
@Override
|
||||
public boolean test(@NotNull final ItemStack[] matrix) {
|
||||
List<ItemStack> dynamicMatrix = Arrays.asList(matrix);
|
||||
boolean matches = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -102,29 +104,38 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
|
||||
}
|
||||
|
||||
char character = String.valueOf(i).toCharArray()[0];
|
||||
ItemStack item = parts.get(i).getItem();
|
||||
|
||||
if (parts.get(i) instanceof TestableStack) {
|
||||
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);
|
||||
List<TestableItem> items = new ArrayList<>();
|
||||
if (parts.get(i) instanceof GroupedTestableItems group) {
|
||||
items.addAll(group.getChildren());
|
||||
} else {
|
||||
items.add(parts.get(i));
|
||||
}
|
||||
|
||||
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(item));
|
||||
}
|
||||
List<ItemStack> displayedItems = new ArrayList<>();
|
||||
|
||||
if (Prerequisite.HAS_1_18.isMet() && !Prerequisite.HAS_PAPER.isMet()) {
|
||||
if (Bukkit.getServer().getRecipe(this.getKey()) != null) {
|
||||
return;
|
||||
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.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@@ -9,28 +8,16 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Utilities / API methods for blocks.
|
||||
*/
|
||||
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,
|
||||
@NotNull final List<Material> allowedMaterials,
|
||||
@NotNull final Set<Block> blocks,
|
||||
@@ -75,12 +62,11 @@ public final class BlockUtils {
|
||||
*
|
||||
* @param player The player to break the block as.
|
||||
* @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,
|
||||
@NotNull final Block block) {
|
||||
Validate.isTrue(initialized, "Must be initialized!");
|
||||
Validate.notNull(blockBreakConsumer, "Must be initialized!");
|
||||
|
||||
Location location = block.getLocation();
|
||||
World world = location.getWorld();
|
||||
assert world != null;
|
||||
@@ -89,7 +75,7 @@ public final class BlockUtils {
|
||||
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() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.util;
|
||||
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -7,10 +8,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Utilities / API methods for numbers.
|
||||
@@ -24,7 +25,7 @@ public final class NumberUtils {
|
||||
/**
|
||||
* Crunch handler.
|
||||
*/
|
||||
private static BiFunction<String, Player, Double> crunch = null;
|
||||
private static CrunchHandler crunch = null;
|
||||
|
||||
/**
|
||||
* Set of roman numerals to look up.
|
||||
@@ -251,7 +252,21 @@ public final class NumberUtils {
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@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.
|
||||
*/
|
||||
@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!");
|
||||
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() {
|
||||
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.ImmutableMap;
|
||||
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 net.kyori.adventure.text.Component;
|
||||
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.legacy.LegacyComponentSerializer;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
@@ -324,17 +323,16 @@ public final class StringUtils {
|
||||
|
||||
private static String processFormatting(@NotNull final String message) {
|
||||
String processedMessage = message;
|
||||
// Run MiniMessage first so it doesn't complain
|
||||
processedMessage = translateMiniMessage(processedMessage);
|
||||
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
|
||||
processedMessage = translateGradients(processedMessage);
|
||||
processedMessage = translateHexColorCodes(processedMessage);
|
||||
if (Prerequisite.HAS_PAPER.isMet()) {
|
||||
processedMessage = translateMiniMessage(processedMessage);
|
||||
}
|
||||
return processedMessage;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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 'me.clip:placeholderapi:2.10.10'
|
||||
compileOnly 'org.reflections:reflections:0.9.12'
|
||||
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
|
||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
|
||||
compileOnly 'net.kyori:adventure-text-minimessage:4.10.0'
|
||||
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
|
||||
compileOnly 'org.objenesis:objenesis:3.2'
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.willfp.eco.internal.config.json
|
||||
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class EcoJSONConfigSection(values: Map<String, Any?>) : EcoJSONConfigWrapper() {
|
||||
class EcoJSONConfigSection(values: Map<String, Any?>, injections: Collection<StaticPlaceholder> = emptyList()) : EcoJSONConfigWrapper() {
|
||||
init {
|
||||
init(values)
|
||||
this.injections = injections.toMutableList()
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
import com.willfp.eco.core.config.interfaces.JSONConfig
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import java.util.Objects
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -22,6 +23,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
val values = ConcurrentHashMap<String, Any?>()
|
||||
|
||||
private val cache = ConcurrentHashMap<String, Any>()
|
||||
var injections = mutableListOf<StaticPlaceholder>()
|
||||
|
||||
fun init(values: Map<String, Any?>) {
|
||||
this.values.clear()
|
||||
@@ -62,7 +64,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
}
|
||||
return if (values[closestPath] is Map<*, *> && path != closestPath) {
|
||||
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)
|
||||
} else {
|
||||
if (values.containsKey(closestPath)) {
|
||||
@@ -88,7 +90,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
for (key in values.keys) {
|
||||
list.add(root + key)
|
||||
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."))
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
closestPath = split[0]
|
||||
}
|
||||
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)
|
||||
values[closestPath] = section.values
|
||||
} else {
|
||||
@@ -130,13 +132,13 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
}
|
||||
|
||||
override fun getSubsection(path: String): JSONConfig {
|
||||
return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf())
|
||||
return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf(), injections)
|
||||
}
|
||||
|
||||
override fun getSubsectionOrNull(path: String): JSONConfig? {
|
||||
return if (values.containsKey(path)) {
|
||||
val subsection = values[path] as Map<String, Any>
|
||||
EcoJSONConfigSection(subsection)
|
||||
EcoJSONConfigSection(subsection, injections)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -147,7 +149,7 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
?: return null
|
||||
val configs = mutableListOf<JSONConfig>()
|
||||
for (map in maps) {
|
||||
configs.add(EcoJSONConfigSection(map))
|
||||
configs.add(EcoJSONConfigSection(map, injections))
|
||||
}
|
||||
return configs.toMutableList()
|
||||
}
|
||||
@@ -206,11 +208,26 @@ open class EcoJSONConfigWrapper : JSONConfig {
|
||||
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 {
|
||||
return ConfigType.JSON
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
import org.bukkit.configuration.ConfigurationSection
|
||||
|
||||
class EcoYamlConfigSection(section: ConfigurationSection) : EcoYamlConfigWrapper<ConfigurationSection>() {
|
||||
class EcoYamlConfigSection(section: ConfigurationSection, injections: Collection<StaticPlaceholder> = emptyList()) : EcoYamlConfigWrapper<ConfigurationSection>() {
|
||||
init {
|
||||
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.interfaces.Config
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.configuration.ConfigurationSection
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
@@ -11,6 +12,7 @@ import java.io.StringReader
|
||||
open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
lateinit var handle: T
|
||||
private val cache = mutableMapOf<String, Any?>()
|
||||
var injections = mutableListOf<StaticPlaceholder>()
|
||||
|
||||
protected fun init(config: T): Config {
|
||||
handle = config
|
||||
@@ -57,7 +59,7 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
if (raw == null) {
|
||||
cache[path] = null
|
||||
} else {
|
||||
cache[path] = EcoYamlConfigSection(raw)
|
||||
cache[path] = EcoYamlConfigSection(raw, injections)
|
||||
}
|
||||
getSubsectionOrNull(path)
|
||||
}
|
||||
@@ -214,7 +216,7 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
for (map in mapList) {
|
||||
val temp = YamlConfiguration.loadConfiguration(StringReader(""))
|
||||
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()
|
||||
@@ -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 {
|
||||
return ConfigType.JSON
|
||||
}
|
||||
@@ -235,7 +252,8 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
StringReader(
|
||||
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>>,
|
||||
private val title: String,
|
||||
private val onClose: CloseHandler
|
||||
): Menu {
|
||||
) : Menu {
|
||||
override fun getSlot(row: Int, column: Int): Slot {
|
||||
if (row < 1 || row > this.rows) {
|
||||
return slots[0][0]
|
||||
@@ -46,7 +46,7 @@ class EcoMenu(
|
||||
if (meta != null) {
|
||||
val lore = meta.lore
|
||||
if (lore != null) {
|
||||
lore.replaceAll{ s -> StringUtils.format(s, player) }
|
||||
lore.replaceAll { s -> StringUtils.format(s, player) }
|
||||
meta.lore = lore
|
||||
}
|
||||
slotItem.itemMeta = meta
|
||||
@@ -103,4 +103,9 @@ class EcoMenu(
|
||||
inventory ?: return HashSet()
|
||||
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