From 3eeca6c3498fd7da1b3949f3a305ff4945cb33fe Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 29 Jan 2023 09:58:52 +0100 Subject: [PATCH] Add CuboidCreator for clipboard cuboid creation Signed-off-by: yoyosource --- .../cuboid/CuboidSchematicWriter.java | 2 +- .../features/cuboid/TypedCuboid.java | 20 -- .../cuboid/clipboard/CuboidCommand.java | 55 +++++ .../cuboid/clipboard/CuboidCreator.java | 190 ++++++++++++++++++ .../bausystem/utils/WorldEditUtils.java | 14 ++ 5 files changed, 260 insertions(+), 21 deletions(-) create mode 100644 BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCommand.java create mode 100644 BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java index 7ca835c4..32d89249 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java @@ -53,7 +53,7 @@ public class CuboidSchematicWriter { // Setup Pos playerPos = new Pos(player.getLocation()); Pos offset = min.sub(playerPos); - Map blocks = CuboidSchematicWriter.getBlocks(player, min, max); + Map blocks = CuboidSchematicWriter.getBlocks(player, min, max); // Needs to be optimized Map> reverseBlocks = reverse(blocks); // Create CuboidSchematic diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java index 55afd8c6..f312ceaa 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java @@ -45,26 +45,6 @@ public class TypedCuboid { this.blockData = blockData; } - public boolean intersects(TypedCuboid cuboid) { - int minx = x - cuboid.dx; - int miny = y - cuboid.dy; - int minz = z - cuboid.dz; - int maxx = minx + dx + cuboid.dx; - int maxy = miny + dy + cuboid.dy; - int maxz = minz + dz + cuboid.dz; - return maxx > cuboid.x && maxy > cuboid.y && maxz > cuboid.z && minx < cuboid.x && miny < cuboid.y && minz < cuboid.z; - } - - public boolean intersects(Pos pos) { - int minx = x - dx; - int miny = y - dy; - int minz = z - dz; - int maxx = minx + dx; - int maxy = miny + dy; - int maxz = minz + dz; - return maxx > pos.x && maxy > pos.y && maxz > pos.z && minx < pos.x && miny < pos.y && minz < pos.z; - } - public long size() { return (long) dx * (long) dy * (long) dz; } diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCommand.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCommand.java new file mode 100644 index 00000000..bf600b7c --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCommand.java @@ -0,0 +1,55 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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.features.cuboid.clipboard; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import de.steamwar.bausystem.utils.WorldEditUtils; +import de.steamwar.command.SWCommand; +import de.steamwar.linkage.Linked; +import org.bukkit.entity.Player; + +import java.util.concurrent.atomic.AtomicInteger; + +@Linked +public class CuboidCommand extends SWCommand { + + public CuboidCommand() { + super("clipboardcuboid"); + } + + @Register + public void onCommand(Player player) { + Clipboard clipboard = WorldEditUtils.getClipboard(player); + if (clipboard == null) { + player.sendMessage("§cDu hast keine Schematic geladen!"); + return; + } + + long time = System.currentTimeMillis(); + AtomicInteger counter = new AtomicInteger(); + new CuboidCreator(clipboard).forEachRemaining(cuboid -> { + counter.incrementAndGet(); + }); + time = System.currentTimeMillis() - time; + player.sendMessage("§aEs wurden " + counter.get() + " Cuboids erstellt!"); + player.sendMessage("§aDas hat " + time + "ms gedauert!"); + player.sendMessage("§aDas sind " + (counter.get() / time) + " Cuboids/ms!"); + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java new file mode 100644 index 00000000..80763148 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java @@ -0,0 +1,190 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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.features.cuboid.clipboard; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import lombok.ToString; +import org.bukkit.Axis; +import org.bukkit.util.Vector; + +import java.util.*; + +public class CuboidCreator implements Iterator { + + private static final List AXES = Arrays.asList( + new Axis[]{Axis.X, Axis.Y, Axis.Z}, + new Axis[]{Axis.X, Axis.Z, Axis.Y}, + new Axis[]{Axis.Y, Axis.X, Axis.Z}, + new Axis[]{Axis.Y, Axis.Z, Axis.X}, + new Axis[]{Axis.Z, Axis.X, Axis.Y}, + new Axis[]{Axis.Z, Axis.Y, Axis.X} + ); + + private Map blocks = new HashMap<>(); + private Map> reverseBlocks = new HashMap<>(); + + private List left = new ArrayList<>(); + + public CuboidCreator(Clipboard clipboard) { + clipboard.getRegion().forEach(blockVector3 -> { + BlockVector3 position = blockVector3.subtract(clipboard.getMinimumPoint()); + BlockState block = clipboard.getBlock(blockVector3); + blocks.put(position, block); + reverseBlocks.computeIfAbsent(block, k -> new HashSet<>()).add(position); + }); + + left.add(BlockVector3.ZERO); + } + + @Override + public boolean hasNext() { + left.removeIf(blockVector3 -> !blocks.containsKey(blockVector3)); + return !left.isEmpty(); + } + + @Override + public Cuboid next() { + BlockVector3 origin = left.get(0); + BlockState block = blocks.get(origin); + + Cuboid cuboid = null; + for (Axis[] axes : AXES) { + Cuboid currentCuboid = new Cuboid(origin, block); + expand(currentCuboid, new ArrayList<>(Arrays.asList(axes))); + if (cuboid == null || cuboid.size() < currentCuboid.size()) { + cuboid = currentCuboid; + } + } + + Set cuboidBlocks = reverseBlocks.get(block); + for (int x = cuboid.x; x < cuboid.x + cuboid.dx; x++) { + for (int y = cuboid.y; y < cuboid.y + cuboid.dy; y++) { + for (int z = cuboid.z; z < cuboid.z + cuboid.dz; z++) { + BlockVector3 pos = BlockVector3.at(x, y, z); + cuboidBlocks.remove(pos); + blocks.remove(pos); + } + } + } + + left.add(BlockVector3.at(origin.getBlockX() + cuboid.dx + 1, origin.getBlockY(), origin.getBlockZ())); + left.add(BlockVector3.at(origin.getBlockX(), origin.getBlockY() + cuboid.dy + 1, origin.getBlockZ())); + left.add(BlockVector3.at(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ() + cuboid.dz + 1)); + return cuboid; + } + + private void expand(Cuboid cuboid, List axes) { + while (!axes.isEmpty()) { + axes.removeIf(axis -> { + org.bukkit.util.Vector direction = new Vector(); + switch (axis) { + case X: + direction.setX(1); + break; + case Y: + direction.setY(1); + break; + case Z: + direction.setZ(1); + break; + } + return !expand(cuboid, direction); + }); + } + } + + private boolean expand(Cuboid cuboid, Vector direction) { + Set blocks = reverseBlocks.get(cuboid.getBlock()); + if (direction.getX() == 1) { + for (int y = cuboid.y; y < cuboid.y + cuboid.dy; y++) { + for (int z = cuboid.z; z < cuboid.z + cuboid.dz; z++) { + if (!blocks.contains(BlockVector3.at(cuboid.x + cuboid.dx + 1, y, z))) { + return false; + } + } + } + } else if (direction.getY() == 1) { + for (int x = cuboid.x; x < cuboid.x + cuboid.dx; x++) { + for (int z = cuboid.z; z < cuboid.z + cuboid.dz; z++) { + if (!blocks.contains(BlockVector3.at(x, cuboid.y + cuboid.dy + 1, z))) { + return false; + } + } + } + } else if (direction.getZ() == 1) { + for (int x = cuboid.x; x < cuboid.x + cuboid.dx; x++) { + for (int y = cuboid.y; y < cuboid.y + cuboid.dy; y++) { + if (!blocks.contains(BlockVector3.at(x, y, cuboid.z + cuboid.dz + 1))) { + return false; + } + } + } + } + if (direction.getX() == 1) { + cuboid.dx++; + } else if (direction.getY() == 1) { + cuboid.dy++; + } else if (direction.getZ() == 1) { + cuboid.dz++; + } + return true; + } + + @ToString + public static class Cuboid { + int x; + int y; + int z; + int dx; + int dy; + int dz; + private BlockState block; + + public Cuboid(BlockVector3 origin, BlockState block) { + this.x = origin.getBlockX(); + this.y = origin.getBlockY(); + this.z = origin.getBlockZ(); + + this.dx = 1; + this.dy = 1; + this.dz = 1; + + this.block = block; + } + + public long size() { + return (long) dx * (long) dy * (long) dz; + } + + public BlockVector3 getOrigin() { + return BlockVector3.at(x, y, z); + } + + public BlockVector3 getSize() { + return BlockVector3.at(dx, dy, dz); + } + + public BlockState getBlock() { + return block; + } + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java b/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java index ec464ef4..d85a9209 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java @@ -20,10 +20,12 @@ package de.steamwar.bausystem.utils; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extension.factory.PatternFactory; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.InputParser; @@ -95,4 +97,16 @@ public class WorldEditUtils { private Location adapt(World world, BlockVector3 blockVector3) { return new Location(world, blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()); } + + public Clipboard getClipboard(Player player) { + try { + return WorldEdit.getInstance() + .getSessionManager() + .get(BukkitAdapter.adapt(player)) + .getClipboard() + .getClipboard(); + } catch (EmptyClipboardException e) { + return null; + } + } }