/* * This file is a part of the SteamWar software. * * Copyright (C) 2025 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package de.steamwar.schematicsystem.autocheck; import de.steamwar.schematicsystem.SchematicSystem; import de.steamwar.sql.GameModeConfig; import lombok.Builder; import lombok.Getter; import lombok.ToString; import net.md_5.bungee.api.chat.ClickEvent; import org.bukkit.Material; import org.bukkit.entity.Player; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Builder @Getter @ToString public class AutoCheckerResult { private final GameModeConfig type; private final int width; private final int height; private final int depth; private final AutoChecker.BlockScanResult blockScanResult; private final List entities; public boolean isOk() { return blockScanResult.getRecords().isEmpty() && blockScanResult.getForbiddenItems().isEmpty() && blockScanResult.getMixedItems().isEmpty() && blockScanResult.getForbiddenNbt().isEmpty() && isSizeOk() && isBlockCountOk() && isLimitedBlocksOK() && isInventoryItemsOK() && !type.isAfterDeadline() && entities.isEmpty() && isDesignBlastResistanceOK(); } public boolean fastOk() { return isSizeOk() && !type.isAfterDeadline(); } public boolean isInventoryItemsOK() { return blockScanResult.getTooManyItems().isEmpty(); } public boolean hasWarnings() { return blockScanResult.getDefunctNbt().isEmpty(); } public boolean isSizeOk() { return !isTooWide() && !isTooHigh() && !isTooDeep(); } public boolean isTooWide() { return width > type.Schematic.Size.x; } public boolean isTooHigh() { return height > type.Schematic.Size.y; } public boolean isTooDeep() { return depth > type.Schematic.Size.z; } public boolean isBlockCountOk() { return type.Schematic.MaxBlocks == 0 || blockScanResult.getBlockCounts().entrySet().stream().filter(entry -> entry.getKey() != Material.AIR).map(Map.Entry::getValue).reduce(Integer::sum).map(i -> i <= type.Schematic.MaxBlocks).orElse(false); } public boolean isLimitedBlocksOK() { return blockScanResult.getBlockCounts().entrySet().stream() .filter(entry -> !type.Schematic.isInventory(entry.getKey())) .allMatch(entry -> entry.getValue() <= type.Schematic.getMaxCount(entry.getKey())) && blockScanResult.getRuleCounts().entrySet().stream() .allMatch(entry -> entry.getValue() <= entry.getKey().Amount); } public boolean isDesignBlastResistanceOK() { return blockScanResult.getDesignBlocks().keySet().stream() .filter(material -> material != Material.WATER && material != Material.LAVA) .map(Material::getBlastResistance).noneMatch(i -> i > type.Schematic.MaxDesignBlastResistance); } public void sendErrorMessage(Player p, String schemName) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_HEADER", p, schemName); if (isTooWide()) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIDTH", p, width, type.Schematic.Size.x); } if (isTooHigh()) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_HEIGHT", p, height, type.Schematic.Size.y); } if (isTooDeep()) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_LENGTH", p, depth, type.Schematic.Size.z); } if (type.Schematic.MaxBlocks != 0 && !isBlockCountOk()) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_BLOCKS", p, blockScanResult.getBlockCounts().values().stream().reduce(Integer::sum).orElse(0), type.Schematic.MaxBlocks); } if (!isLimitedBlocksOK()) { blockScanResult.getBlockCounts().forEach((mat, count) -> { if (type.Schematic.isInventory(mat)) return; int maxCount = type.Schematic.getMaxCount(mat); if (count > maxCount) { if (maxCount == 0) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK", p, mat.name()); } else { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_BLOCK", p, mat.name(), count, maxCount); } } }); blockScanResult.getRuleCounts().forEach((rule, count) -> { if (count <= rule.Amount) return; String blocks = blockScanResult.getRuleBlockTypes().get(rule).stream().map(Material::name).collect(Collectors.joining(", ")); if (rule.Amount == 0) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK", p, blocks); } else { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_BLOCK", p, blocks, count, rule.Amount); } }); } blockScanResult.getTooManyItems().forEach((pos, caps) -> { Material inventory = blockScanResult.getInventoryBlockType().get(pos); caps.forEach((itemType, cap) -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_INVENTORY_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), blockScanResult.getInventoryItemCounts().get(pos).get(itemType), cap, itemType.name(), inventory.name()); }); }); blockScanResult.getRecords().forEach(blockVector3 -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_RECORD", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()); }); blockScanResult.getForbiddenItems().forEach((blockVector3, materials) -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_ITEM", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), setToString(materials)); }); blockScanResult.getMixedItems().forEach((blockVector3, materials) -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_MIXED_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), setToString(materials)); }); blockScanResult.getForbiddenNbt().forEach((blockVector3, materials) -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), setToString(materials)); }); blockScanResult.getDefunctNbt().forEach(blockVector3 -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_DEFUNCT_NBT", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()); }); blockScanResult.getDesignBlocks().forEach((material, poss) -> { if (material == Material.WATER || material == Material.LAVA) return; if (material.getBlastResistance() > type.Schematic.MaxDesignBlastResistance) { poss.forEach(pos -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_DESIGN_BLOCK", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), material.name(), pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); }); } }); entities.forEach(blockPos -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_ENTITY", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockPos), blockPos.getX(), blockPos.getY(), blockPos.getZ()); }); if (type.isAfterDeadline()) { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_AFTER_DEADLINE", p, type.Deadline); } } private static ClickEvent tpCommandTo(BlockPos pos) { return new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tp " + pos.getBlockX() + " " + pos.getBlockY() + " " + pos.getBlockZ()); } private static String setToString(Collection set) { return set.stream().map(material -> material.getKey().getKey()).reduce((s, s2) -> s + "§7, §c" + s2).orElse(""); } }