diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/DetectionTask.java b/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/DetectionTask.java index 1cf1eff8c..6a58b98e7 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/DetectionTask.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/DetectionTask.java @@ -26,6 +26,7 @@ import net.countercraft.movecraft.processing.tasks.detection.validators.PilotSignValidator; import net.countercraft.movecraft.processing.tasks.detection.validators.SizeValidator; import net.countercraft.movecraft.processing.tasks.detection.validators.WaterContactValidator; +import net.countercraft.movecraft.processing.tasks.detection.validators.LiquidBlockValidator; import net.countercraft.movecraft.util.AtomicLocationSet; import net.countercraft.movecraft.util.CollectionUtils; import net.countercraft.movecraft.util.Tags; @@ -95,7 +96,8 @@ public class DetectionTask implements Supplier { private static final List>>> COMPLETION_VALIDATORS = List.of( new SizeValidator(), new FlyBlockValidator(), - new DetectionBlockValidator() + new DetectionBlockValidator(), + new LiquidBlockValidator() ); private static final List>>> VISITED_VALIDATORS = List.of( new WaterContactValidator() diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/validators/LiquidBlockValidator.java b/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/validators/LiquidBlockValidator.java new file mode 100644 index 000000000..42a77b6d5 --- /dev/null +++ b/Movecraft/src/main/java/net/countercraft/movecraft/processing/tasks/detection/validators/LiquidBlockValidator.java @@ -0,0 +1,91 @@ +package net.countercraft.movecraft.processing.tasks.detection.validators; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.type.CraftType; +import net.countercraft.movecraft.processing.MovecraftWorld; +import net.countercraft.movecraft.processing.functions.DetectionPredicate; +import net.countercraft.movecraft.processing.functions.Result; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Deque; +import java.util.Map; + +public class LiquidBlockValidator implements DetectionPredicate>> { + @Override + public @NotNull Result validate(@NotNull Map> materialDequeMap, @NotNull CraftType type, @NotNull MovecraftWorld world, @Nullable Player player) { + String allowedAmountString = type.getStringProperty(CraftType.LIQUIDS_MAX_AMOUNT); + boolean blockNumber = !allowedAmountString.startsWith("N"); //if false use block percentage + final String errorMessage = "Too many waterlogged blocks on craft"; + + int maxAmount; + try { + if (blockNumber) { + maxAmount = Integer.parseInt(allowedAmountString.substring(1)); + } else { + maxAmount = Integer.parseInt(allowedAmountString); + } + } catch (NumberFormatException e) { + return Result.failWithMessage("liquidsMaxAmount wasn't configurated properly"); + } + + final int liquidBlocks = getLiquidAmount(materialDequeMap, world); + if (liquidBlocks == 0) + return Result.succeed(); + + if (maxAmount == 0) + return Result.failWithMessage(errorMessage); + + if(blockNumber) { + if (liquidBlocks <= maxAmount) { + return Result.succeed(); + } else { + return Result.failWithMessage(errorMessage); + } + } else { + int allBlocks = getTotalBlocks(materialDequeMap); + double percentage = ((double) liquidBlocks / allBlocks) * 100; + + if (percentage <= maxAmount) { + return Result.succeed(); + } else { + return Result.failWithMessage(errorMessage); + } + } + } + + public int getLiquidAmount(Map> materialDequeMap, MovecraftWorld world) { + int amount = 0; + for (var locationList : materialDequeMap.entrySet()) { + final Deque locations = locationList.getValue(); + + if (locationList.getKey() == Material.WATER || locationList.getKey() == Material.BUBBLE_COLUMN) { + amount += locations.size(); + continue; + } + + for (var location : locations) { + BlockData blockData = world.getData(location); + + if (blockData instanceof Waterlogged waterlogged && waterlogged.isWaterlogged()) { + amount++; + } + } + } + + return amount; + } + + public int getTotalBlocks(Map> materialDequeMap) { + int amount = 0; + for (var locationList : materialDequeMap.values()) { + amount += locationList.size(); + } + + return amount; + } +} diff --git a/api/src/main/java/net/countercraft/movecraft/craft/type/CraftType.java b/api/src/main/java/net/countercraft/movecraft/craft/type/CraftType.java index d0f66b287..840b4e56b 100644 --- a/api/src/main/java/net/countercraft/movecraft/craft/type/CraftType.java +++ b/api/src/main/java/net/countercraft/movecraft/craft/type/CraftType.java @@ -82,6 +82,7 @@ final public class CraftType { private static final NamespacedKey CAN_FLY = buildKey("can_fly"); // Private key used to calculate BLOCKED_BY_WATER public static final NamespacedKey REQUIRE_WATER_CONTACT = buildKey("require_water_contact"); + public static final NamespacedKey LIQUIDS_MAX_AMOUNT = buildKey("liquids_max_amount"); public static final NamespacedKey TRY_NUDGE = buildKey("try_nudge"); public static final NamespacedKey MOVE_BLOCKS = buildKey("move_blocks"); public static final NamespacedKey CAN_CRUISE = buildKey("can_cruise"); @@ -412,6 +413,7 @@ public static void registerTypeValidator(Predicate validator, String registerProperty(new BooleanProperty("blockedByWater", BLOCKED_BY_WATER, type -> true)); registerProperty(new BooleanProperty("canFly", CAN_FLY, type -> type.getBoolProperty(BLOCKED_BY_WATER))); registerProperty(new BooleanProperty("requireWaterContact", REQUIRE_WATER_CONTACT, type -> false)); + registerProperty(new StringProperty("liquidsMaxAmount", LIQUIDS_MAX_AMOUNT, type -> "0")); registerProperty(new BooleanProperty("tryNudge", TRY_NUDGE, type -> false)); registerProperty(new RequiredBlockProperty("moveblocks", MOVE_BLOCKS, type -> new HashSet<>())); registerProperty(new BooleanProperty("canCruise", CAN_CRUISE, type -> false));