/* * 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().y()) .width(clipboard.getDimensions().x()) .depth(clipboard.getDimensions().z()) .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().y()) .width(clipboard.getDimensions().x()) .depth(clipboard.getDimensions().z()) .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.x(); x <= max.x(); x++) { for (int y = min.y(); y <= max.y(); y++) { for (int z = min.z(); z <= max.z(); z++) { final BaseBlock block = clipboard.getFullBlock(BlockVector3.at(x, y, z)); final Material material = Material.matchMaterial(block.getBlockType().id()); if (material == null) { continue; } BlockPos pos = new BlockPos(x, y, z); if (type.Schematic.isInventory(material)) { checkInventory(result, block, material, pos, type); if (!result.getInventoryItemCounts().getOrDefault(pos, Collections.emptyMap()).isEmpty()) { result.getBlockCounts().merge(material, 1, Integer::sum); } } else { result.getBlockCounts().merge(material, 1, Integer::sum); } if (x == min.x() || x == max.x() || y == max.y() || z == min.z() || z == max.z()) { result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(pos); } } } } return result; } 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 Map itemCounts = new EnumMap<>(Material.class); 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 (type.Schematic.getItemAmount(material, itemType) == 0) { result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } else { itemCounts.merge(itemType, item.getInt("count"), Integer::sum); } if (item.containsKey("tag")) { result.getForbiddenNbt().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } } if (!itemCounts.isEmpty()) { result.getInventoryItemCounts().put(pos, itemCounts); result.getInventoryBlockType().put(pos, material); } 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> inventoryItemCounts = new HashMap<>(); private final Map inventoryBlockType = new HashMap<>(); private final Map windChargeCount = new HashMap<>(); private final Map> forbiddenItems = new HashMap<>(); private final Map> forbiddenNbt = new HashMap<>(); } }