From b7a92793131e856987d184482bbb2e6196434928 Mon Sep 17 00:00:00 2001 From: froobynooby Date: Sun, 28 Apr 2024 12:06:52 +0930 Subject: [PATCH] Improve warnings for incorrect entity types in profiles --- .../controller/ProfileManager.java | 17 +++- .../farmcontrol/group/GroupDefinition.java | 59 +++++++++--- .../farmcontrol/utils/EntityCategory.java | 96 +++++++++++++++++++ 3 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/froobworld/farmcontrol/utils/EntityCategory.java diff --git a/src/main/java/com/froobworld/farmcontrol/controller/ProfileManager.java b/src/main/java/com/froobworld/farmcontrol/controller/ProfileManager.java index 73e2c9b..b8179e6 100644 --- a/src/main/java/com/froobworld/farmcontrol/controller/ProfileManager.java +++ b/src/main/java/com/froobworld/farmcontrol/controller/ProfileManager.java @@ -3,6 +3,7 @@ import com.froobworld.farmcontrol.FarmControl; import com.froobworld.farmcontrol.controller.action.Action; import com.froobworld.farmcontrol.group.GroupDefinition; +import com.froobworld.farmcontrol.utils.EntityCategory; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -10,6 +11,7 @@ import java.io.IOException; import java.nio.file.Files; import java.util.*; +import java.util.stream.Collectors; public class ProfileManager { private final FarmControl farmControl; @@ -33,7 +35,7 @@ public void load() throws IOException { for (String name : Objects.requireNonNull(profilesSection).getKeys(false)) { try { ConfigurationSection profileSection = Objects.requireNonNull(profilesSection.getConfigurationSection(name)); - GroupDefinition groupDefinition = GroupDefinition.fromConfigurationSection(Objects.requireNonNull(profileSection.getConfigurationSection("group"))); + GroupDefinition groupDefinition = GroupDefinition.fromConfigurationSection(farmControl, name, Objects.requireNonNull(profileSection.getConfigurationSection("group"))); Set actions = new HashSet<>(); for (String actionName : profileSection.getStringList("actions")) { Action action = farmControl.getActionManager().getAction(actionName.toLowerCase()); @@ -41,10 +43,23 @@ public void load() throws IOException { farmControl.getLogger().warning("Unknown action for profile '" + name + "': '" + actionName.toLowerCase() + "'"); continue; } + Set incompatibleCategories = new HashSet<>(); + for (EntityCategory memberCategory : groupDefinition.getMemberCategories()) { + if (!memberCategory.isCompatibleWith(action)) { + incompatibleCategories.add(memberCategory.getName()); + } + } + if (!incompatibleCategories.isEmpty()) { + String incompatibleCategoriesString = incompatibleCategories.stream() + .map(Object::toString) + .collect(Collectors.joining(", ")); + farmControl.getLogger().warning("Note: action '" + actionName + "' in profile '" + name + "' is incompatible with the following entity types: " + incompatibleCategoriesString); + } actions.add(action); } actionProfileMap.put(name, new ActionProfile(groupDefinition, actions)); } catch (Exception ex) { + ex.printStackTrace(); farmControl.getLogger().warning("Unable to load the profile '" + name + "'. Incorrect syntax?"); } } diff --git a/src/main/java/com/froobworld/farmcontrol/group/GroupDefinition.java b/src/main/java/com/froobworld/farmcontrol/group/GroupDefinition.java index 19ea1c3..325c54a 100644 --- a/src/main/java/com/froobworld/farmcontrol/group/GroupDefinition.java +++ b/src/main/java/com/froobworld/farmcontrol/group/GroupDefinition.java @@ -1,12 +1,17 @@ package com.froobworld.farmcontrol.group; +import com.froobworld.farmcontrol.FarmControl; import com.froobworld.farmcontrol.controller.entity.SnapshotEntity; -import com.froobworld.farmcontrol.utils.EntityTypeUtils; +import com.froobworld.farmcontrol.utils.EntityCategory; import org.bukkit.configuration.ConfigurationSection; +import java.util.HashSet; +import java.util.Set; import java.util.function.Predicate; public class GroupDefinition { + private final Set memberCategories; + private final Set excludedCategories; private final Predicate typePredicate; private final Predicate excludeTypePredicate; private final int size; @@ -16,15 +21,31 @@ public class GroupDefinition { private final boolean ignoreVerticalDistance; private final boolean pure; - public GroupDefinition(Predicate typePredicate, Predicate excludeTypePredicate, int size, double distance, boolean sameChunk, boolean ignoreVerticalDistance, boolean pure) { - this.typePredicate = typePredicate; - this.excludeTypePredicate = excludeTypePredicate; + public GroupDefinition(Set memberCategories, Set excludedCategories, int size, double distance, boolean sameChunk, boolean ignoreVerticalDistance, boolean pure) { + this.memberCategories = memberCategories; + this.excludedCategories = excludedCategories; this.size = size; this.distance = distance; this.distanceSquared = distance * distance; this.sameChunk = sameChunk; this.ignoreVerticalDistance = ignoreVerticalDistance; this.pure = pure; + this.typePredicate = memberCategories.stream() + .map(EntityCategory::asSnapshotEntityPredicate) + .reduce(Predicate::or) + .orElse(snapshotEntity -> false); // require explicit specification of types by defaulting to false + this.excludeTypePredicate = excludedCategories.stream() + .map(EntityCategory::asSnapshotEntityPredicate) + .reduce(Predicate::or) + .orElse(snapshotEntity -> false); + } + + public Set getMemberCategories() { + return memberCategories; + } + + public Set getExcludedCategories() { + return excludedCategories; } public Predicate getTypePredicate() { @@ -59,22 +80,32 @@ public boolean isPure() { return pure; } - public static GroupDefinition fromConfigurationSection(ConfigurationSection section) { - Predicate typePredicate = section.getStringList("types").stream() - .map(EntityTypeUtils::fromString) - .reduce(Predicate::or) - .orElse(snapshotEntity -> false); // require explicit specification of types by defaulting to false - Predicate excludeTypePredicate = section.getStringList("exclude-types").stream() - .map(EntityTypeUtils::fromString) - .reduce(Predicate::or) - .orElse(snapshotEntity -> false); + public static GroupDefinition fromConfigurationSection(FarmControl farmControl, String profileName, ConfigurationSection section) { + Set memberCategories = new HashSet<>(); + for (String entityType : section.getStringList("types")) { + EntityCategory entityCategory = EntityCategory.ofName(entityType); + if (entityCategory == null) { + farmControl.getLogger().warning("Unknown entity type '" + entityType + "' for profile '" + profileName + "'."); + } else { + memberCategories.add(entityCategory); + } + } + Set excludedCategories = new HashSet<>(); + for (String entityType : section.getStringList("exclude-types")) { + EntityCategory entityCategory = EntityCategory.ofName(entityType); + if (entityCategory == null) { + farmControl.getLogger().warning("Unknown excluded entity type '" + entityType + "' for profile '" + profileName + "'."); + } else { + excludedCategories.add(entityCategory); + } + } int size = section.getInt("count"); boolean sameChunk = section.isString("distance") && "same-chunk".equalsIgnoreCase(section.getString("distance")); double distance = sameChunk ? 0 : section.getDouble("distance"); boolean ignoreVerticalDistance = section.getBoolean("ignore-vertical-distance"); boolean pure = section.getBoolean("pure"); - return new GroupDefinition(typePredicate, excludeTypePredicate, size, distance, sameChunk, ignoreVerticalDistance, pure); + return new GroupDefinition(memberCategories, excludedCategories, size, distance, sameChunk, ignoreVerticalDistance, pure); } } diff --git a/src/main/java/com/froobworld/farmcontrol/utils/EntityCategory.java b/src/main/java/com/froobworld/farmcontrol/utils/EntityCategory.java new file mode 100644 index 0000000..28d08f8 --- /dev/null +++ b/src/main/java/com/froobworld/farmcontrol/utils/EntityCategory.java @@ -0,0 +1,96 @@ +package com.froobworld.farmcontrol.utils; + +import com.froobworld.farmcontrol.controller.action.Action; +import com.froobworld.farmcontrol.controller.entity.SnapshotEntity; +import org.bukkit.entity.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class EntityCategory { + private static final Map entityCategoryMap; + private final String name; + private final boolean allowInheritance; + private final Class[] memberClasses; + + static { + List entityCategories = new ArrayList<>(); + for (EntityType entityType : EntityType.values()) { + Class entityTypeClass = entityType.getEntityClass(); + if (entityTypeClass != null) { + entityCategories.add(new EntityCategory(entityType.toString().toLowerCase(), false, entityTypeClass)); + } + } + entityCategories.addAll( + List.of( + new EntityCategory("category:animal", true, Animals.class), + new EntityCategory("category:monster", true, Monster.class), + new EntityCategory("category:golem", true, Golem.class), + new EntityCategory("category:ambient", true, Ambient.class), + new EntityCategory("category:fish", true, Fish.class), + new EntityCategory("category:tameable", true, Tameable.class), + new EntityCategory("category:raider", true, Raider.class), + new EntityCategory("category:mob", true, Mob.class), + new EntityCategory("category:vehicle", true, Boat.class, Minecart.class), + new EntityCategory("category:projectile", true, Projectile.class) + ) + ); + + entityCategoryMap = new HashMap<>(); + entityCategories.forEach(entityCategory -> entityCategoryMap.put(entityCategory.name, entityCategory)); + } + + private EntityCategory(String name, boolean allowInheritance, Class... memberClasses) { + this.name = name; + this.allowInheritance = allowInheritance; + this.memberClasses = memberClasses; + } + + public String getName() { + return name; + } + + public boolean isMember(Class entityClass) { + for (Class memberClass : memberClasses) { + if (allowInheritance ? memberClass.isAssignableFrom(entityClass) : memberClass.equals(entityClass)) { + return true; + } + } + return false; + } + + public boolean isMember(SnapshotEntity entity) { + return isMember(entity.getEntityClass()); + } + + public boolean isMember(EntityType entityType) { + if (entityType.getEntityClass() == null) { + return false; + } + return isMember(entityType.getEntityClass()); + } + + public Predicate asSnapshotEntityPredicate() { + return this::isMember; + } + + public boolean isCompatibleWith(Action action) { + for (EntityType entityType : EntityType.values()) { + if (isMember(entityType)) { + Class entityTypeClass = entityType.getEntityClass(); + if (entityTypeClass != null && action.getEntityClass().isAssignableFrom(entityTypeClass)) { + return true; + } + } + } + return false; + } + + public static EntityCategory ofName(String categoryName) { + return EntityCategory.entityCategoryMap.get(categoryName); + } + +}