/* * 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.bausystem.utils; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.pattern.WaterloggedRemover; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import de.steamwar.bausystem.region.Point; import de.steamwar.bausystem.region.flags.ColorMode; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import lombok.Getter; import lombok.NonNull; import java.io.File; import java.io.IOException; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiPredicate; @Getter public class PasteBuilder { private final ClipboardProvider clipboardProvider; private Point pastPoint; private boolean rotate; private boolean ignoreAir; private boolean reset; private Point minPoint; private Point maxPoint; private int waterLevel; private List> predicates = new ArrayList<>(); private List> mappers = new ArrayList<>(); public PasteBuilder(@NonNull ClipboardProvider clipboardProvider) { this.clipboardProvider = clipboardProvider; } public PasteBuilder pastePoint(Point point) { this.pastPoint = point; return this; } public PasteBuilder rotate(boolean rotate) { this.rotate = rotate; return this; } public PasteBuilder ignoreAir(boolean ignoreAir) { this.ignoreAir = ignoreAir; return this; } public PasteBuilder reset(boolean reset) { this.reset = reset; return this; } public PasteBuilder minPoint(Point point) { this.minPoint = point; return this; } public PasteBuilder maxPoint(Point point) { this.maxPoint = point; return this; } public PasteBuilder waterLevel(int waterLevel) { this.waterLevel = waterLevel; return this; } public PasteBuilder only(BiPredicate predicate) { predicates.add(predicate); return this; } public PasteBuilder map(BiConsumer mapper) { mappers.add(mapper); return this; } public PasteBuilder color(ColorMode color) { if (color == ColorMode.PINK) return this; Map blockCache = new HashMap<>(); return map((clipboard, blockVector3) -> { BaseBlock block = clipboard.getFullBlock(blockVector3); if (block.getBlockType().getId().startsWith("minecraft:pink_")) { BaseBlock baseBlock = blockCache.computeIfAbsent(block.getBlockType().getId(), s -> { String replaced = s.replace("minecraft:pink_", "minecraft:" + color.name().toLowerCase() + "_"); BlockType blockType = BlockTypes.get(replaced); if (blockType == null) return null; return blockType.getDefaultState().toBaseBlock(); }); if (baseBlock == null) return; clipboard.setBlock(blockVector3, baseBlock); } }); } /** * Can only be used before {@link #color(ColorMode)}. */ public PasteBuilder onlyColors(boolean onlyColors) { if (!onlyColors) return this; return only((baseBlock, s) -> s.startsWith("minecraft:pink_")); } public PasteBuilder removeTNT(boolean removeTNT) { if (!removeTNT) return this; BaseBlock tnt = Objects.requireNonNull(BlockTypes.get("tnt")).getDefaultState().toBaseBlock(); BaseBlock air = Objects.requireNonNull(BlockTypes.get("air")).getDefaultState().toBaseBlock(); return map((clipboard, blockVector3) -> { BaseBlock baseBlock = clipboard.getFullBlock(blockVector3); if (baseBlock.equals(tnt)) { clipboard.setBlock(blockVector3, air); } }); } public PasteBuilder removeWater(boolean removeWater) { if (!removeWater) return this; BaseBlock water = Objects.requireNonNull(BlockTypes.get("water")).getDefaultState().toBaseBlock(); BlockType bubble_column_type = BlockTypes.get("bubble_column"); BaseBlock bubble_column; if (bubble_column_type == null) { bubble_column = null; } else { bubble_column = bubble_column_type.getDefaultState().toBaseBlock(); } BaseBlock air = Objects.requireNonNull(BlockTypes.get("air")).getDefaultState().toBaseBlock(); WaterloggedRemover waterloggedRemover = new WaterloggedRemover(getClipboard()); return map((clipboard, blockVector3) -> { BaseBlock baseBlock = clipboard.getFullBlock(blockVector3); if (baseBlock.equals(water)) { clipboard.setBlock(blockVector3, air); return; } if (bubble_column != null && baseBlock.equals(bubble_column)) { clipboard.setBlock(blockVector3, air); return; } String blockName = clipboard.getFullBlock(blockVector3).getBlockType().getName(); if (blockName.equals("Water")) { clipboard.setBlock(blockVector3, air); return; } baseBlock = waterloggedRemover.applyBlock(blockVector3); if (baseBlock != air) { clipboard.setBlock(blockVector3, baseBlock); } }); } public Clipboard getClipboard() { return clipboardProvider.getClipboard(); } public EditSession run() { if (pastPoint == null) { throw new IllegalStateException("pastePoint is null"); } return FlatteningWrapper.impl.paste(this); } public interface ClipboardProvider { Clipboard getClipboard(); default boolean is(Class clazz) { return clazz.isInstance(this); } default T as(Class clazz) { return clazz.cast(this); } } @Getter public static class FileProvider implements ClipboardProvider { private final File file; private final Clipboard clipboard; public FileProvider(File file) { this.file = file; this.clipboard = FlatteningWrapper.impl.loadSchematic(file); } @Override public Clipboard getClipboard() { return clipboard; } } @Getter public static class SchematicProvider implements ClipboardProvider { private final SchematicNode schematic; private final Clipboard clipboard; public SchematicProvider(SchematicNode schematic) { this.schematic = schematic; try { this.clipboard = new SchematicData(schematic).load(); } catch (IOException e) { throw new SecurityException(e); } } @Override public Clipboard getClipboard() { return clipboard; } } @Getter public static class ClipboardProviderImpl implements ClipboardProvider { private final Clipboard clipboard; public ClipboardProviderImpl(Clipboard clipboard) { this.clipboard = clipboard; } @Override public Clipboard getClipboard() { return clipboard; } } }