Added deserializers for all target goals

This commit is contained in:
Auxilor
2022-03-02 14:13:49 +00:00
parent 88a7fb53a3
commit a35f5bb405
15 changed files with 477 additions and 11 deletions

View File

@@ -18,10 +18,9 @@ public final class EntityGoals {
*/
private static final Map<NamespacedKey, KeyedDeserializer<? extends EntityGoal<?>>> BY_KEY = HashBiMap.create();
/**
* minecraft:avoid_entity.
*/
public static final KeyedDeserializer<EntityGoalAvoidEntity> AVOID_ENTITY = register(EntityGoalAvoidEntity.DESERIALIZER);
static {
register(EntityGoalAvoidEntity.DESERIALIZER);
}
/**
* Get deserializer by key.
@@ -34,7 +33,15 @@ public final class EntityGoals {
return BY_KEY.get(key);
}
private static <T extends KeyedDeserializer<? extends EntityGoal<?>>> T register(@NotNull final T toRegister) {
/**
* 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;
}

View File

@@ -0,0 +1,68 @@
package com.willfp.eco.core.entities.ai;
import com.google.common.collect.HashBiMap;
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.TargetGoalOwnerHurt;
import com.willfp.eco.core.entities.ai.target.TargetGoalOwnerHurtBy;
import com.willfp.eco.core.entities.ai.target.TargetGoalResetUniversalAnger;
import com.willfp.eco.core.serialization.KeyedDeserializer;
import org.bukkit.NamespacedKey;
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(TargetGoalOwnerHurt.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<?>> getByKey(@NotNull final NamespacedKey key) {
return BY_KEY.get(key);
}
/**
* 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");
}
}

View File

@@ -36,6 +36,9 @@ public record EntityGoalAvoidEntity(
*/
public static final KeyedDeserializer<EntityGoalAvoidEntity> DESERIALIZER = new Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
private static final class Deserializer implements KeyedDeserializer<EntityGoalAvoidEntity> {
@Override

View File

@@ -1,12 +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");
}
}
}

View File

@@ -1,9 +1,14 @@
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.EntityType;
import org.bukkit.entity.LivingEntity;
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.
@@ -14,5 +19,48 @@ import org.jetbrains.annotations.NotNull;
public record TargetGoalHurtBy(
@NotNull Class<? extends LivingEntity>... blacklist
) implements TargetGoal<Mob> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalHurtBy> DESERIALIZER = new TargetGoalHurtBy.Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
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(
(Class<? extends LivingEntity>[])
config.getStrings("blacklist").stream()
.map(String::toUpperCase)
.map(EntityType::valueOf)
.map(EntityType::getEntityClass)
.toArray()
);
} 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");
}
}
}

View File

@@ -1,10 +1,18 @@
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.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -23,5 +31,56 @@ public record TargetGoalNearestAttackable(
int reciprocalChance,
@NotNull Predicate<LivingEntity> targetFilter
) implements TargetGoal<Mob> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalNearestAttackable> DESERIALIZER = new TargetGoalNearestAttackable.Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestAttackable> {
@Override
@Nullable
public TargetGoalNearestAttackable deserialize(@NotNull final Config config) {
if (!(
config.has("targetClass")
&& config.has("checkVisibility")
&& config.has("checkCanNavigate")
&& config.has("reciprocalChance")
&& config.has("targetFilter")
)) {
return null;
}
try {
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestAttackable(
(Class<? extends LivingEntity>)
Objects.requireNonNull(
EntityType.valueOf(config.getString("avoidClass").toUpperCase()).getEntityClass()
),
config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance"),
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("nearest_attackable");
}
}
}

View File

@@ -1,10 +1,18 @@
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.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Raider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -23,5 +31,56 @@ public record TargetGoalNearestAttackableWitch(
int reciprocalChance,
@NotNull Predicate<LivingEntity> targetFilter
) implements TargetGoal<Raider> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalNearestAttackableWitch> DESERIALIZER = new TargetGoalNearestAttackableWitch.Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestAttackableWitch> {
@Override
@Nullable
public TargetGoalNearestAttackableWitch deserialize(@NotNull final Config config) {
if (!(
config.has("targetClass")
&& config.has("checkVisibility")
&& config.has("checkCanNavigate")
&& config.has("reciprocalChance")
&& config.has("targetFilter")
)) {
return null;
}
try {
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestAttackableWitch(
(Class<? extends LivingEntity>)
Objects.requireNonNull(
EntityType.valueOf(config.getString("avoidClass").toUpperCase()).getEntityClass()
),
config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance"),
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("nearest_attackable_witch");
}
}
}

View File

@@ -1,10 +1,18 @@
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.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Raider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -19,5 +27,52 @@ public record TargetGoalNearestHealableRaider(
boolean checkVisibility,
@NotNull Predicate<LivingEntity> targetFilter
) implements TargetGoal<Raider> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalNearestHealableRaider> DESERIALIZER = new TargetGoalNearestHealableRaider.Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
private static final class Deserializer implements KeyedDeserializer<TargetGoalNearestHealableRaider> {
@Override
@Nullable
public TargetGoalNearestHealableRaider deserialize(@NotNull final Config config) {
if (!(
config.has("targetClass")
&& config.has("checkVisibility")
&& config.has("targetFilter")
)) {
return null;
}
try {
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestHealableRaider(
(Class<? extends LivingEntity>)
Objects.requireNonNull(
EntityType.valueOf(config.getString("avoidClass").toUpperCase()).getEntityClass()
),
config.getBool("checkVisibility"),
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("nearest_healable_raider");
}
}
}

View File

@@ -1,10 +1,18 @@
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.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Tameable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -19,5 +27,52 @@ public record TargetGoalNonTameRandom(
boolean checkVisibility,
@NotNull Predicate<LivingEntity> targetFilter
) implements TargetGoal<Tameable> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalNonTameRandom> DESERIALIZER = new TargetGoalNonTameRandom.Deserializer();
/**
* Deserialize configs into the goal.
*/
@SuppressWarnings("unchecked")
private static final class Deserializer implements KeyedDeserializer<TargetGoalNonTameRandom> {
@Override
@Nullable
public TargetGoalNonTameRandom deserialize(@NotNull final Config config) {
if (!(
config.has("targetClass")
&& config.has("checkVisibility")
&& config.has("targetFilter")
)) {
return null;
}
try {
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNonTameRandom(
(Class<? extends LivingEntity>)
Objects.requireNonNull(
EntityType.valueOf(config.getString("avoidClass").toUpperCase()).getEntityClass()
),
config.getBool("checkVisibility"),
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("non_tame_random");
}
}
}

View File

@@ -1,12 +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 TargetGoalOwnerHurt(
) implements TargetGoal<Tameable> {
/**
* The deserializer for the goal.
*/
public static final KeyedDeserializer<TargetGoalOwnerHurt> DESERIALIZER = new TargetGoalOwnerHurt.Deserializer();
/**
* Deserialize configs into the goal.
*/
private static final class Deserializer implements KeyedDeserializer<TargetGoalOwnerHurt> {
@Override
public TargetGoalOwnerHurt deserialize(@NotNull final Config config) {
return new TargetGoalOwnerHurt();
}
@NotNull
@Override
public NamespacedKey getKey() {
return NamespacedKey.minecraft("owner_hurt");
}
}
}

View File

@@ -1,12 +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");
}
}
}

View File

@@ -1,7 +1,12 @@
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.
@@ -13,5 +18,42 @@ import org.bukkit.entity.Mob;
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");
}
}
}

View File

@@ -6,6 +6,9 @@ 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.
*/

View File

@@ -3,11 +3,10 @@ package com.willfp.eco.core.serialization;
import org.bukkit.Keyed;
/**
* Deserialize objects from configs.
* <p>
* Has a key.
* Deserializer with a key.
*
* @param <T> The type of object to deserialize.
* @see ConfigDeserializer
*/
public interface KeyedDeserializer<T> extends ConfigDeserializer<T>, Keyed {

View File

@@ -3,11 +3,10 @@ package com.willfp.eco.core.serialization;
import org.bukkit.Keyed;
/**
* Serialize objects to configs.
* <p>
* Has a key.
* Serializer with a key.
*
* @param <T> The type of object to serialize.
* @see ConfigSerializer
*/
public interface KeyedSerializer<T> extends ConfigSerializer<T>, Keyed {