/* * 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.core.Core; 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; @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.getForbiddenNbt().isEmpty() && isSizeOk() && isBlockCountOk() && isLimitedBlocksOK() && isDispenserItemsOK() && isWindchargeCountOK() && !type.isAfterDeadline() && entities.isEmpty() && isDesignBlastResistanceOK(); } public boolean fastOk() { return isSizeOk() && !type.isAfterDeadline(); } public boolean isWindchargeCountOK() { if( type.Schematic.Type.getName().equals("wargearseason26")) { int windChargesCount = blockScanResult.getWindChargeCount().values().stream().reduce(Integer::sum).orElse(0); return windChargesCount <= 2048; } else { return true; } } public boolean isDispenserItemsOK() { return blockScanResult.getDispenserItems().values().stream().allMatch(i -> i <= type.Schematic.MaxDispenserItems); } 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() { try { return type.Schematic.Limited.entrySet().stream() .map(setIntegerEntry -> setIntegerEntry.getKey().stream().map(blockScanResult.getBlockCounts()::get).map(i -> i == null || i <= setIntegerEntry.getValue()).reduce(Boolean::logicalAnd).orElse(false)) .reduce(Boolean::logicalAnd).orElse(true); } catch (NullPointerException e) { return false; } } 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()) { type.Schematic.Limited.forEach((materials, integer) -> { for (Material mat : materials) { if(mat != null && blockScanResult.getBlockCounts().getOrDefault(mat, 0) > integer) { if(integer == 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(), blockScanResult.getBlockCounts().getOrDefault(mat, 0), integer); } } } }); } if(!isWindchargeCountOK()) { int windChargesCount = blockScanResult.getWindChargeCount().values().stream().reduce(Integer::sum).orElse(0); SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIND_CHARGES", p, windChargesCount, 2048); blockScanResult.getWindChargeCount().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > 0).forEach(blockVector3IntegerEntry -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIND_CHARGES_DISPENSER", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3IntegerEntry.getKey()), blockVector3IntegerEntry.getKey().getBlockX(), blockVector3IntegerEntry.getKey().getBlockY(), blockVector3IntegerEntry.getKey().getBlockZ(), blockVector3IntegerEntry.getValue()); }); } blockScanResult.getDispenserItems().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > type.Schematic.MaxDispenserItems).forEach(blockVector3IntegerEntry -> { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3IntegerEntry.getKey()), blockVector3IntegerEntry.getKey().getBlockX(), blockVector3IntegerEntry.getKey().getBlockY(), blockVector3IntegerEntry.getKey().getBlockZ(), blockVector3IntegerEntry.getValue(), type.Schematic.MaxDispenserItems); }); 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.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(""); } }