/* * 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 com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import de.steamwar.sql.GameModeConfig; import lombok.Getter; import lombok.ToString; import org.bukkit.Material; import java.util.*; import java.util.stream.Collectors; public class AutoChecker { public static final AutoChecker impl = new AutoChecker(); public AutoCheckerResult check(Clipboard clipboard, GameModeConfig type) { return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX()) .depth(clipboard.getDimensions().getBlockZ()).blockScanResult(scan(clipboard, type)) .entities(clipboard.getEntities().stream().map(Entity::getLocation) .map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ())) .collect(Collectors.toList())) .build(); } public AutoCheckerResult sizeCheck(Clipboard clipboard, GameModeConfig type) { return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX()) .depth(clipboard.getDimensions().getBlockZ()).build(); } public AutoChecker.BlockScanResult scan(Clipboard clipboard, GameModeConfig type) { AutoChecker.BlockScanResult result = new AutoChecker.BlockScanResult(); BlockVector3 min = clipboard.getMinimumPoint(); BlockVector3 max = clipboard.getMaximumPoint(); for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { final BaseBlock block = clipboard.getFullBlock(BlockVector3.at(x, y, z)); final Material material = Material.matchMaterial(block.getBlockType().getId()); if (material == null) { continue; } result.getBlockCounts().merge(material, 1, Integer::sum); if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) { checkInventory(result, block, material, new BlockPos(x, y, z), type); } if (x == min.getBlockX() || x == max.getBlockX() || y == max.getBlockY() || z == min.getBlockZ() || z == max.getBlockZ()) { result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z)); } } } } return result; } private static final Map> itemsInInv = new EnumMap<>(Material.class); static { itemsInInv.put(Material.BUCKET, EnumSet.of(Material.DISPENSER)); itemsInInv.put(Material.TNT, EnumSet.of(Material.CHEST, Material.BARREL, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX)); itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER)); itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER)); AutoCheckerItems.impl.getAllowedMaterialsInInventory().forEach(material -> itemsInInv.put(material, AutoCheckerItems.impl.getInventoryMaterials())); } private void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, Material material, BlockPos pos, GameModeConfig type) { CompoundTag nbt = block.getNbtData(); if (nbt == null) { result.getDefunctNbt().add(pos); return; } if (material == Material.JUKEBOX && nbt.getValue().containsKey("RecordItem")) { result.getRecords().add(pos); return; } List items = nbt.getList("Items", CompoundTag.class); if (items.isEmpty()) return; // Leeres Inventar int counter = 0; int windChargeCount = 0; for (CompoundTag item : items) { if (!item.containsKey("id")) { result.getDefunctNbt().add(pos); continue; } Material itemType = Material.matchMaterial(item.getString("id")); if (itemType == null) // Leere Slots continue; if(type.Schematic.Type.getName().equals("wargearseason26") && material == Material.DISPENSER && itemType == Material.WIND_CHARGE) { windChargeCount += item.getInt("count"); } else if (!itemsInInv.getOrDefault(itemType, EnumSet.noneOf(Material.class)).contains(material)) { result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } else if (material == Material.DISPENSER && (itemType == Material.ARROW || itemType == Material.FIRE_CHARGE)) { counter += item.getInt("count"); } if (item.containsKey("tag")) { result.getForbiddenNbt().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } } result.getDispenserItems().put(pos, counter); result.getWindChargeCount().put(pos, windChargeCount); } @Getter @ToString public static class BlockScanResult { private final Map blockCounts = new EnumMap<>(Material.class); private final List defunctNbt = new ArrayList<>(); private final List records = new ArrayList<>(); private final Map> designBlocks = new EnumMap<>(Material.class); private final Map dispenserItems = new HashMap<>(); private final Map windChargeCount = new HashMap<>(); private final Map> forbiddenItems = new HashMap<>(); private final Map> forbiddenNbt = new HashMap<>(); } }