diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CSchemClipboardFormat.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CSchemClipboardFormat.java new file mode 100644 index 00000000..1fdd8174 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CSchemClipboardFormat.java @@ -0,0 +1,79 @@ +/* + * 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; + +import com.fastasyncworldedit.core.internal.io.parallelgzip.ParallelGZIPOutputStream; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import de.steamwar.bausystem.features.cuboid.io.CSchemWriter; + +import java.io.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.zip.GZIPOutputStream; + +public class CSchemClipboardFormat implements ClipboardFormat { + + @Override + public String getName() { + return "CSchem"; + } + + @Override + public Set getAliases() { + return new HashSet<>(Arrays.asList("cschem")); + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + return null; + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + OutputStream gzip; + if (!(outputStream instanceof ParallelGZIPOutputStream) && !(outputStream instanceof GZIPOutputStream)) { + OutputStream outputStreamx = new BufferedOutputStream(outputStream); + gzip = new GZIPOutputStream(outputStreamx); + } else { + gzip = outputStream; + } + + return new CSchemWriter(new NBTOutputStream(new BufferedOutputStream(gzip))); + } + + @Override + public boolean isFormat(File file) { + return file.getName().endsWith(".cschem"); + } + + @Override + public String getPrimaryFileExtension() { + return "cschem"; + } + + @Override + public Set getFileExtensions() { + return new HashSet<>(Arrays.asList("cschem")); + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Cuboid.java similarity index 60% rename from BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java rename to BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Cuboid.java index f312ceaa..b3519893 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/TypedCuboid.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Cuboid.java @@ -19,33 +19,45 @@ package de.steamwar.bausystem.features.cuboid; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; import lombok.ToString; @ToString -public class TypedCuboid { +public class Cuboid { + int x; + int y; + int z; + int dx; + int dy; + int dz; + private BlockState block; - public int x; - public int y; - public int z; - public int dx; - public int dy; - public int dz; - - public String blockData; - - public TypedCuboid(int x, int y, int z, String blockData) { - this.x = x; - this.y = y; - this.z = z; + 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.blockData = blockData; + 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/features/cuboid/Cuboid2Command.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Cuboid2Command.java deleted file mode 100644 index 68464b3f..00000000 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Cuboid2Command.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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; - -import de.steamwar.bausystem.shared.Pair; -import de.steamwar.bausystem.utils.WorldEditUtils; -import de.steamwar.command.SWCommand; -import de.steamwar.linkage.Linked; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPOutputStream; - -@Linked -public class Cuboid2Command extends SWCommand { - - public Cuboid2Command() { - super("cuboid"); - } - - @Register - public void command(Player player) { - Pair selection = WorldEditUtils.getSelection(player); - if (selection == null) { - player.sendMessage("§cDu musst erst eine Auswahl treffen!"); - return; - } - Location min = selection.getKey(); - Location max = selection.getValue(); - - Vector minVec = new Vector(Math.min(min.getX(), max.getX()), Math.min(min.getY(), max.getY()), Math.min(min.getZ(), max.getZ())); - Vector maxVec = new Vector(Math.max(min.getX(), max.getX()), Math.max(min.getY(), max.getY()), Math.max(min.getZ(), max.getZ())); - - CuboidSchematicWriter cuboidSchematicWriter = new CuboidSchematicWriter(minVec, maxVec); - cuboidSchematicWriter.create(player, cuboidSchematic -> { - AtomicInteger counter = new AtomicInteger(); - try { - cuboidSchematic.write(new GZIPOutputStream(new OutputStream() { - @Override - public void write(int b) throws IOException { - counter.incrementAndGet(); - } - })); - } catch (IOException e) { - throw new RuntimeException(e); - } - player.sendMessage("§aDie Schematic ist " + counter.get() + " Bytes groß!"); - System.out.println(cuboidSchematic); - }); - } -} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidClipboard.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidClipboard.java new file mode 100644 index 00000000..b23a083d --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidClipboard.java @@ -0,0 +1,86 @@ +/* + * 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; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +@Getter +public class CuboidClipboard implements Clipboard { + + private Clipboard parent; + private List cuboids; + private Map order; + + public CuboidClipboard(Clipboard parent, List cuboids, Map order) { + this.parent = parent; + this.cuboids = cuboids; + this.order = order; + } + + @Override + public Region getRegion() { + return parent.getRegion(); + } + + @Override + public BlockVector3 getDimensions() { + return parent.getDimensions(); + } + + @Override + public BlockVector3 getOrigin() { + return parent.getOrigin(); + } + + @Override + public void setOrigin(BlockVector3 origin) { + parent.setOrigin(origin); + } + + @Override + public void removeEntity(Entity entity) { + parent.removeEntity(entity); + } + + @Override + public BlockVector3 getMinimumPoint() { + return parent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return parent.getMaximumPoint(); + } + + @Override + public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + return false; + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCommand.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCommand.java index 6f33f813..8b170b1d 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCommand.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCommand.java @@ -19,182 +19,77 @@ package de.steamwar.bausystem.features.cuboid; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import de.steamwar.bausystem.BauSystem; -import de.steamwar.bausystem.shared.Pair; import de.steamwar.bausystem.utils.WorldEditUtils; import de.steamwar.command.SWCommand; -import lombok.ToString; -import org.bukkit.Axis; -import org.bukkit.Location; -import org.bukkit.Material; +import de.steamwar.linkage.Linked; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import java.util.*; -import java.util.function.Supplier; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; -// @Linked +@Linked public class CuboidCommand extends SWCommand { + static { + ClipboardFormats.registerClipboardFormat(new CSchemClipboardFormat()); + } + public CuboidCommand() { super("cuboid"); } @Register - public void genericCommand(Player player) { - Pair selection = WorldEditUtils.getSelection(player); - if (selection == null) { - player.sendMessage("§cDu musst erst eine Auswahl treffen!"); + public void onCommand(Player player) { + Clipboard clipboard = WorldEditUtils.getClipboard(player); + if (clipboard == null) { + player.sendMessage("§cDu hast keine Schematic geladen!"); return; } - Location min = selection.getKey(); - Location max = selection.getValue(); - - Vector minVec = new Vector(Math.min(min.getX(), max.getX()), Math.min(min.getY(), max.getY()), Math.min(min.getZ(), max.getZ())); - Vector maxVec = new Vector(Math.max(min.getX(), max.getX()), Math.max(min.getY(), max.getY()), Math.max(min.getZ(), max.getZ())); - - Map blocks = new HashMap<>(); - 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++) { - blocks.put(new Vector(x, y, z), player.getWorld().getBlockAt(x, y, z).getType()); - } - } - } - - List left = new ArrayList<>(); - left.add(minVec); long time = System.currentTimeMillis(); - List cuboids = new ArrayList<>(); - runTickEfficient(left::isEmpty, () -> { - System.out.println(left.size()); - Vector current = left.remove(0); - if (current.getX() > maxVec.getX() || current.getY() > maxVec.getY() || current.getZ() > maxVec.getZ()) { - return; + CuboidCreator4 cuboidCreator4 = new CuboidCreator4(clipboard); + runAsync(cuboidCreator4, cuboids -> { + long t2 = System.currentTimeMillis() - time; + player.sendMessage("§aEs wurden " + cuboids.size() + " Cuboids erstellt!"); + player.sendMessage("§aDas hat " + t2 + "ms gedauert!"); + player.sendMessage("§aDas sind " + (cuboids.size() / (double) Math.max(t2, 1)) + " Cuboids/ms!"); + + CuboidClipboard cuboidClipboard = new CuboidClipboard(clipboard, cuboids, cuboidCreator4.applyOrder()); + AtomicLong size = new AtomicLong(); + try { + cuboidClipboard.save(new OutputStream() { + @Override + public void write(int b) throws IOException { + size.incrementAndGet(); + } + }, ClipboardFormats.findByAlias("cschem")); + } catch (IOException e) { } - - BlockCuboid cuboid = new BlockCuboid(current, blocks.get(current)); - expand(cuboid, maxVec, blocks); - cuboids.add(cuboid); - - left.add(new Vector(cuboid.min.getX(), cuboid.min.getY(), cuboid.max.getZ() + 1)); - left.add(new Vector(cuboid.min.getX(), cuboid.max.getY() + 1, cuboid.min.getZ())); - left.add(new Vector(cuboid.max.getX() + 1, cuboid.min.getY(), cuboid.min.getZ())); - }, () -> { - System.out.println((System.currentTimeMillis() - time) + " ms " + cuboids); + player.sendMessage("§aDie Größe der Schematic beträgt " + size.get() + " Bytes!"); }); } - private void runTickEfficient(Supplier finished, Runnable next, Runnable finishedCallback) { + private void runAsync(Iterator iterator, Consumer> result) { new BukkitRunnable() { + private final List list = new ArrayList<>(); + @Override public void run() { - if (finished.get()) { - cancel(); - finishedCallback.run(); - return; - } - long time = System.currentTimeMillis(); - while (System.currentTimeMillis() - time < 50) { - if (finished.get()) { - cancel(); - finishedCallback.run(); - return; - } - next.run(); - } + iterator.forEachRemaining(list::add); + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { + result.accept(list); + }, 1); } - }.runTaskTimer(BauSystem.getInstance(), 0, 1); - } - - @ToString - private static class BlockCuboid { - private final Vector min; - private final Vector max; - private final Material material; - - public BlockCuboid(Vector min, Material material) { - this.min = min.clone(); - this.max = min.clone(); - this.material = material; - } - } - - private void expand(BlockCuboid cuboid, Vector max, Map blocks) { - List axes = new ArrayList<>(); - axes.add(Axis.X); - axes.add(Axis.Y); - axes.add(Axis.Z); - do { - Vector sizes = cuboid.max.clone().subtract(cuboid.min).add(new Vector(1, 1, 1)); - axes.sort(Comparator.comparing(axis -> { - switch (axis) { - case X: - return sizes.getX(); - case Y: - return sizes.getY(); - case Z: - return sizes.getZ(); - default: - return 0.0; - } - })); - axes.removeIf(axis -> { - 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, max, direction, blocks); - }); - } while (!axes.isEmpty()); - } - - private boolean expand(BlockCuboid cuboid, Vector max, Vector direction, Map blocks) { - if (direction.getX() == 1) { - if (cuboid.max.getX() + 1 > max.getX()) { - return false; - } - for (double y = cuboid.min.getY(); y <= cuboid.max.getY(); y++) { - for (double z = cuboid.min.getZ(); z <= cuboid.max.getZ(); z++) { - if (blocks.get(new Vector(cuboid.max.getX() + 1, y, z)) != cuboid.material) { - return false; - } - } - } - } else if (direction.getY() == 1) { - if (cuboid.max.getY() + 1 > max.getY()) { - return false; - } - for (double x = cuboid.min.getX(); x <= cuboid.max.getX(); x++) { - for (double z = cuboid.min.getZ(); z <= cuboid.max.getZ(); z++) { - if (blocks.get(new Vector(x, cuboid.max.getY() + 1, z)) != cuboid.material) { - return false; - } - } - } - } else if (direction.getZ() == 1) { - if (cuboid.max.getZ() + 1 > max.getZ()) { - return false; - } - for (double x = cuboid.min.getX(); x <= cuboid.max.getX(); x++) { - for (double y = cuboid.min.getY(); y <= cuboid.max.getY(); y++) { - if (blocks.get(new Vector(x, y, cuboid.max.getZ() + 1)) != cuboid.material) { - return false; - } - } - } - } - cuboid.max.add(direction); - return true; + }.runTaskAsynchronously(BauSystem.getInstance()); } } diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator.java similarity index 80% rename from BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java rename to BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator.java index 80763148..320ec368 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCreator.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator.java @@ -17,18 +17,17 @@ * along with this program. If not, see . */ -package de.steamwar.bausystem.features.cuboid.clipboard; +package de.steamwar.bausystem.features.cuboid; 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 { +public class CuboidCreator implements Iterator { private static final List AXES = Arrays.asList( new Axis[]{Axis.X, Axis.Y, Axis.Z}, @@ -86,9 +85,9 @@ public class CuboidCreator implements Iterator { } } - 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)); + left.add(BlockVector3.at(origin.getBlockX() + cuboid.dx, origin.getBlockY(), origin.getBlockZ())); + left.add(BlockVector3.at(origin.getBlockX(), origin.getBlockY() + cuboid.dy, origin.getBlockZ())); + left.add(BlockVector3.at(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ() + cuboid.dz)); return cuboid; } @@ -117,7 +116,7 @@ public class CuboidCreator implements Iterator { 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))) { + if (!blocks.contains(BlockVector3.at(cuboid.x + cuboid.dx, y, z))) { return false; } } @@ -125,7 +124,7 @@ public class CuboidCreator implements Iterator { } 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))) { + if (!blocks.contains(BlockVector3.at(x, cuboid.y + cuboid.dy, z))) { return false; } } @@ -133,7 +132,7 @@ public class CuboidCreator implements Iterator { } 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))) { + if (!blocks.contains(BlockVector3.at(x, y, cuboid.z + cuboid.dz))) { return false; } } @@ -148,43 +147,4 @@ public class CuboidCreator implements Iterator { } 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/features/cuboid/CuboidCreator2.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator2.java new file mode 100644 index 00000000..a2b5abe4 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator2.java @@ -0,0 +1,147 @@ +/* + * 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; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import org.bukkit.Axis; +import org.bukkit.util.Vector; + +import java.util.*; + +public class CuboidCreator2 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> reverseBlocks = new HashMap<>(); + + public CuboidCreator2(Clipboard clipboard) { + clipboard.getRegion().forEach(blockVector3 -> { + BlockVector3 position = blockVector3.subtract(clipboard.getMinimumPoint()); + BlockState block = clipboard.getBlock(blockVector3); + reverseBlocks.computeIfAbsent(block, k -> new HashSet<>()).add(position); + }); + } + + @Override + public boolean hasNext() { + return !reverseBlocks.isEmpty(); + } + + @Override + public Cuboid next() { + Cuboid cuboid = null; + BlockState toRemove = null; + for (Map.Entry> entry : reverseBlocks.entrySet()) { + BlockState block = entry.getKey(); + Set positions = entry.getValue(); + + for (BlockVector3 position : positions) { + for (Axis[] axes : AXES) { + Cuboid currentCuboid = new Cuboid(position, block); + expand(currentCuboid, new ArrayList<>(Arrays.asList(axes)), entry.getValue()); + if (cuboid == null || cuboid.size() < currentCuboid.size()) { + cuboid = currentCuboid; + } + } + } + + 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++) { + positions.remove(BlockVector3.at(x, y, z)); + } + } + } + if (positions.isEmpty()) { + toRemove = block; + } + break; + } + if (toRemove != null) { + reverseBlocks.remove(toRemove); + } + return cuboid; + } + + private void expand(Cuboid cuboid, List axes, Set blocks) { + while (!axes.isEmpty()) { + axes.removeIf(axis -> { + org.bukkit.util.Vector direction = new org.bukkit.util.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, blocks); + }); + } + } + + private boolean expand(Cuboid cuboid, Vector direction, Set blocks) { + 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, 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, 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))) { + return false; + } + } + } + } + if (direction.getX() == 1) { + cuboid.dx++; + } else if (direction.getY() == 1) { + cuboid.dy++; + } else if (direction.getZ() == 1) { + cuboid.dz++; + } + return true; + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator3.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator3.java new file mode 100644 index 00000000..daf8c955 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator3.java @@ -0,0 +1,169 @@ +/* + * 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; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import org.bukkit.Axis; +import org.bukkit.Material; +import org.bukkit.util.Vector; + +import java.util.*; + +public class CuboidCreator3 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 static final Set invisible = new HashSet<>(); + static { + for (Material value : Material.values()) { + if (!value.isOccluding() || value.isAir()) { + invisible.add("minecraft:" + value.name().toLowerCase()); + } + } + } + + private Set invisibleBlocks = new HashSet<>(); + private Map> reverseBlocks = new HashMap<>(); + + public CuboidCreator3(Clipboard clipboard) { + clipboard.getRegion().forEach(blockVector3 -> { + BlockVector3 position = blockVector3.subtract(clipboard.getMinimumPoint()); + BlockState block = clipboard.getBlock(blockVector3); + if (block.getAsString().startsWith("minecraft:redstone_wire") && !block.getAsString().equals("minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none]")) { + block = BlockState.get("minecraft:redstone_wire[east=side,north=side,power=0,south=side,west=side]"); + } + reverseBlocks.computeIfAbsent(block, k -> new HashSet<>()).add(position); + if (invisible.contains(block.getBlockType().getId())) { + invisibleBlocks.add(position); + } + }); + } + + @Override + public boolean hasNext() { + return !reverseBlocks.isEmpty(); + } + + @Override + public Cuboid next() { + Cuboid cuboid = null; + BlockState toRemove = null; + for (Map.Entry> entry : reverseBlocks.entrySet()) { + BlockState block = entry.getKey(); + Set positions = entry.getValue(); + + for (BlockVector3 position : positions) { + for (Axis[] axes : AXES) { + Cuboid currentCuboid = new Cuboid(position, block); + expand(currentCuboid, new ArrayList<>(Arrays.asList(axes)), entry.getValue()); + if (cuboid == null || cuboid.size() < currentCuboid.size()) { + cuboid = currentCuboid; + } + } + } + + 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++) { + positions.remove(BlockVector3.at(x, y, z)); + } + } + } + if (positions.isEmpty()) { + toRemove = block; + } + break; + } + if (toRemove != null) { + reverseBlocks.remove(toRemove); + } + return cuboid; + } + + private void expand(Cuboid cuboid, List axes, Set blocks) { + while (!axes.isEmpty()) { + axes.removeIf(axis -> { + 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, blocks); + }); + } + } + + private boolean expand(Cuboid cuboid, Vector direction, Set blocks) { + boolean selfInvisible = invisibleBlocks.contains(BlockVector3.at(cuboid.x, cuboid.y, cuboid.z)); + 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++) { + BlockVector3 pos = BlockVector3.at(cuboid.x + cuboid.dx, y, z); + if (!blocks.contains(pos) && (!invisibleBlocks.contains(pos) || selfInvisible)) { + 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++) { + BlockVector3 pos = BlockVector3.at(x, cuboid.y + cuboid.dy, z); + if (!blocks.contains(pos) && (!invisibleBlocks.contains(pos) || selfInvisible)) { + 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++) { + BlockVector3 pos = BlockVector3.at(x, y, cuboid.z + cuboid.dz); + if (!blocks.contains(pos) && (!invisibleBlocks.contains(pos) || selfInvisible)) { + return false; + } + } + } + } + if (direction.getX() == 1) { + cuboid.dx++; + } else if (direction.getY() == 1) { + cuboid.dy++; + } else if (direction.getZ() == 1) { + cuboid.dz++; + } + return true; + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator4.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator4.java new file mode 100644 index 00000000..1be0b2d8 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidCreator4.java @@ -0,0 +1,181 @@ +/* + * 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; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import org.bukkit.Axis; +import org.bukkit.util.Vector; + +import java.util.*; + +public class CuboidCreator4 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 List invisibleOrder = new ArrayList<>(); + private Map> invisible = new HashMap<>(); + + private Map blocks = new HashMap<>(); + private Map> reverseBlocks = new HashMap<>(); + + public CuboidCreator4(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); + }); + invisibleOrder.addAll(reverseBlocks.keySet()); + invisibleOrder.sort(Comparator.comparingInt(o -> -reverseBlocks.get(o).size())); + invisibleOrder.remove(BlockState.get("minecraft:air")); + invisibleOrder.add(BlockState.get("minecraft:air")); + for (int i = 0; i < invisibleOrder.size(); i++) { + BlockState block = invisibleOrder.get(i); + for (int j = i + 1; j < invisibleOrder.size(); j++) { + invisible.computeIfAbsent(block, k -> new HashSet<>()).add(invisibleOrder.get(j)); + } + } + } + + public Map applyOrder() { + Map order = new HashMap<>(); + for (int i = 0; i < invisibleOrder.size(); i++) { + order.put(invisibleOrder.get(i), i); + } + return order; + } + + @Override + public boolean hasNext() { + return !reverseBlocks.isEmpty(); + } + + @Override + public Cuboid next() { + Cuboid cuboid = null; + BlockState toRemove = null; + for (Map.Entry> entry : reverseBlocks.entrySet()) { + BlockState block = entry.getKey(); + List positions = new ArrayList<>(entry.getValue()); + + for (int i = 0; i < positions.size(); i++) { + BlockVector3 position = positions.get(i); + for (Axis[] axes : AXES) { + Cuboid currentCuboid = new Cuboid(position, block); + expand(currentCuboid, new ArrayList<>(Arrays.asList(axes)), entry.getValue()); + if (cuboid == null || cuboid.size() < currentCuboid.size()) { + cuboid = currentCuboid; + if (cuboid.size() > positions.size()) { + break; + } + } + } + if (cuboid.size() > positions.size()) { + break; + } + } + + 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++) { + entry.getValue().remove(BlockVector3.at(x, y, z)); + } + } + } + if (entry.getValue().isEmpty()) { + toRemove = block; + } + break; + } + if (toRemove != null) { + reverseBlocks.remove(toRemove); + } + return cuboid; + } + + private void expand(Cuboid cuboid, List axes, Set blocks) { + while (!axes.isEmpty()) { + axes.removeIf(axis -> { + 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, blocks); + }); + } + } + + private boolean expand(Cuboid cuboid, Vector direction, Set blocks) { + Set invisible = this.invisible.getOrDefault(cuboid.getBlock(), new HashSet<>()); + 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++) { + BlockVector3 pos = BlockVector3.at(cuboid.x + cuboid.dx, y, z); + if (!blocks.contains(pos) && !invisible.contains(this.blocks.get(pos))) { + 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++) { + BlockVector3 pos = BlockVector3.at(x, cuboid.y + cuboid.dy, z); + if (!blocks.contains(pos) && !invisible.contains(this.blocks.get(pos))) { + 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++) { + BlockVector3 pos = BlockVector3.at(x, y, cuboid.z + cuboid.dz); + if (!blocks.contains(pos) && !invisible.contains(this.blocks.get(pos))) { + return false; + } + } + } + } + if (direction.getX() == 1) { + cuboid.dx++; + } else if (direction.getY() == 1) { + cuboid.dy++; + } else if (direction.getZ() == 1) { + cuboid.dz++; + } + return true; + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematic.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematic.java deleted file mode 100644 index 5505d15a..00000000 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematic.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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; - -import com.sk89q.jnbt.*; -import lombok.Getter; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Getter -public class CuboidSchematic { - private Pos offset; - private Pos size; - private Map> cuboids = new HashMap<>(); - - public CuboidSchematic(Pos offset, Pos size) { - this.offset = offset; - this.size = size; - } - - public void addCuboid(TypedCuboid cuboid) { - cuboids.computeIfAbsent(cuboid.blockData, s -> new ArrayList<>()).add(cuboid); - } - - public void write(OutputStream outputStream) { - Map schematic = new HashMap<>(); - schematic.put("OffsetX", new IntTag(offset.x)); - schematic.put("OffsetY", new IntTag(offset.y)); - schematic.put("OffsetZ", new IntTag(offset.z)); - schematic.put("SizeX", new IntTag(size.x)); - schematic.put("SizeY", new IntTag(size.y)); - schematic.put("SizeZ", new IntTag(size.z)); - - Map cuboidMap = new HashMap<>(); - for (Map.Entry> entry : cuboids.entrySet()) { - byte[] cuboidArray = new byte[entry.getValue().size() * 15]; - for (int i = 0; i < entry.getValue().size(); i++) { - TypedCuboid cuboid = entry.getValue().get(i); - List bytes = new ArrayList<>(); - writeVarInt(cuboid.x, bytes); - writeVarInt(cuboid.y, bytes); - writeVarInt(cuboid.z, bytes); - writeVarInt(cuboid.dx, bytes); - writeVarInt(cuboid.dy, bytes); - writeVarInt(cuboid.dz, bytes); - } - cuboidMap.put(entry.getKey(), new ByteArrayTag(cuboidArray)); - } - schematic.put("Cuboids", new CompoundTag(cuboidMap)); - - CompoundTag compoundTag = new CompoundTag(schematic); - try { - NBTOutputStream nbtOutputStream = new NBTOutputStream(outputStream); - nbtOutputStream.writeTag(compoundTag); - nbtOutputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private static void writeVarInt(int value, List bytes) { - while (true) { - if (value < 128) { - bytes.add((byte) value); - return; - } else { - bytes.add((byte) (value & 127 | 128)); - value >>>= 7; - } - } - } -} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java deleted file mode 100644 index 32d89249..00000000 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/CuboidSchematicWriter.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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; - -import de.steamwar.bausystem.BauSystem; -import org.bukkit.Axis; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Consumer; -import org.bukkit.util.Vector; - -import java.util.*; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class CuboidSchematicWriter { - - 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 Pos min; - private Pos max; - - public CuboidSchematicWriter(Vector min, Vector max) { - this.min = new Pos(min); - this.max = new Pos(max); - } - - public void create(Player player, Consumer consumer) { - // Setup - Pos playerPos = new Pos(player.getLocation()); - Pos offset = min.sub(playerPos); - Map blocks = CuboidSchematicWriter.getBlocks(player, min, max); // Needs to be optimized - Map> reverseBlocks = reverse(blocks); - - // Create CuboidSchematic - CuboidSchematic schematic = new CuboidSchematic(offset, max.sub(min)); - - // Create Cuboids - long time = System.currentTimeMillis(); - List left = new ArrayList<>(); - left.add(new Pos(0, 0, 0)); - runTickEfficient(left::isEmpty, () -> { - Pos current = left.remove(0); - String block = blocks.remove(current); - if (block == null) { - return; - } - - TypedCuboid cuboid = null; - for (Axis[] axes : AXES) { - TypedCuboid currentCuboid = new TypedCuboid(current.x, current.y, current.z, block); - expand(currentCuboid, new ArrayList<>(Arrays.asList(axes)), reverseBlocks); - if (cuboid == null || currentCuboid.size() > cuboid.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++) { - Pos pos = new Pos(x, y, z); - cuboidBlocks.remove(pos); - blocks.remove(pos); - } - } - } - schematic.addCuboid(cuboid); - - left.add(new Pos(current.x + cuboid.dx + 1, current.y, current.z)); - left.add(new Pos(current.x, current.y + cuboid.dy + 1, current.z)); - left.add(new Pos(current.x, current.y, current.z + cuboid.dz + 1)); - }, () -> { - long elapsed = System.currentTimeMillis() - time; - long cuboids = schematic.getCuboids().values().stream().mapToLong(List::size).sum(); - System.out.println("Finished in " + elapsed + "ms with " + cuboids + " cuboids"); - System.out.println("Average: " + (cuboids / elapsed) + " cuboids per ms"); - System.out.println("Types: " + schematic.getCuboids().entrySet().stream().map(e -> e.getKey() + ": " + e.getValue().size()).collect(Collectors.joining(", "))); - consumer.accept(schematic); - }); - } - - private void runTickEfficient(Supplier finished, Runnable next, Runnable finishedCallback) { - new BukkitRunnable() { - @Override - public void run() { - long time = System.currentTimeMillis(); - while (System.currentTimeMillis() - time < 50) { - if (finished.get()) { - cancel(); - finishedCallback.run(); - return; - } - next.run(); - } - } - }.runTaskTimer(BauSystem.getInstance(), 0, 1); - } - - private static Map getBlocks(Player player, Pos min, Pos max) { - Map blocks = new HashMap<>(); - 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++) { - blocks.put(new Pos(x - min.x, y - min.y, z - min.z), player.getWorld().getBlockAt(x, y, z).getBlockData().getAsString()); - } - } - } - return blocks; - } - - private static Map> reverse(Map input) { - Map> output = new HashMap<>(); - for (Map.Entry entry : input.entrySet()) { - output.computeIfAbsent(entry.getValue(), k -> new HashSet<>()).add(entry.getKey()); - } - return output; - } - - private static void expand(TypedCuboid cuboid, List axes, Map> reverseBlocks) { - while (!axes.isEmpty()) { - axes.removeIf(axis -> { - 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, reverseBlocks); - }); - } - } - - private static boolean expand(TypedCuboid cuboid, Vector direction, Map> reverseBlocks) { - Set blocks = reverseBlocks.get(cuboid.blockData); - 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(new Pos(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(new Pos(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(new Pos(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; - } -} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Pos.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Pos.java deleted file mode 100644 index e746d750..00000000 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/Pos.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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; - -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.bukkit.Location; -import org.bukkit.util.Vector; - -@ToString -@EqualsAndHashCode -public class Pos { - public final int x; - public final int y; - public final int z; - - public Pos(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - - public Pos(Location loc) { - this.x = loc.getBlockX(); - this.y = loc.getBlockY(); - this.z = loc.getBlockZ(); - } - - public Pos(Vector vec) { - this.x = vec.getBlockX(); - this.y = vec.getBlockY(); - this.z = vec.getBlockZ(); - } - - public Pos add(int x, int y, int z) { - return new Pos(this.x + x, this.y + y, this.z + z); - } - - public Pos add(Pos pos) { - return new Pos(this.x + pos.x, this.y + pos.y, this.z + pos.z); - } - - public Pos sub(int x, int y, int z) { - return new Pos(this.x - x, this.y - y, this.z - z); - } - - public Pos sub(Pos pos) { - return new Pos(this.x - pos.x, this.y - pos.y, this.z - pos.z); - } -} 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 deleted file mode 100644 index d0fc8978..00000000 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/clipboard/CuboidCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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() / Math.max(time, 1)) + " Cuboids/ms!"); - } -} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/io/CSchemWriter.java b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/io/CSchemWriter.java new file mode 100644 index 00000000..2d8fb7ca --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/cuboid/io/CSchemWriter.java @@ -0,0 +1,151 @@ +/* + * 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.io; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; +import de.steamwar.bausystem.features.cuboid.Cuboid; +import de.steamwar.bausystem.features.cuboid.CuboidClipboard; +import de.steamwar.bausystem.features.cuboid.CuboidCreator; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CSchemWriter implements ClipboardWriter { + + private static final int CURRENT_VERSION = 1; + private final NBTOutputStream outputStream; + + public CSchemWriter(NBTOutputStream outputStream) { + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard) throws IOException { + if (!(clipboard instanceof CuboidClipboard)) { + List cuboidList = new ArrayList<>(); + new CuboidCreator(clipboard).forEachRemaining(cuboidList::add); + clipboard = new CuboidClipboard(clipboard, cuboidList, new HashMap<>()); + } + CuboidClipboard cuboidClipboard = (CuboidClipboard) clipboard; + + Region region = clipboard.getRegion(); + BlockVector3 origin = clipboard.getOrigin(); + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 offset = min.subtract(origin); + + outputStream.writeLazyCompoundTag("Schematic", out -> { + out.writeNamedTag("DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()); + out.writeNamedTag("Version", CURRENT_VERSION); + List bs = new ArrayList<>(); + writeVarInt(region.getWidth(), bs); + writeVarInt(region.getHeight(), bs); + writeVarInt(region.getLength(), bs); + writeVarInt(min.getBlockX(), bs); + writeVarInt(min.getBlockY(), bs); + writeVarInt(min.getBlockZ(), bs); + writeVarInt(offset.getBlockX(), bs); + writeVarInt(offset.getBlockY(), bs); + writeVarInt(offset.getBlockZ(), bs); + byte[] bsArray = new byte[bs.size()]; + for (int i = 0; i < bsArray.length; i++) { + bsArray[i] = bs.get(i); + } + out.writeNamedTag("SizeMinOffset", new ByteArrayTag(bsArray)); + + List cuboids = cuboidClipboard.getCuboids(); + Map> cuboidMap = new HashMap<>(); + for (Cuboid cuboid : cuboids) { + cuboidMap.computeIfAbsent(cuboid.getBlock(), k -> new ArrayList<>()).add(cuboid); + } + + out.writeLazyCompoundTag("Cuboids", out1 -> { + BlockState mostBytes = null; + int mostBytesSize = 0; + + Map cuboidBytes = new HashMap<>(); + for (Map.Entry> entry : cuboidMap.entrySet()) { + List bytes = new ArrayList<>(); + writeVarInt(cuboidClipboard.getOrder().getOrDefault(entry.getKey(), 0), bytes); + for (Cuboid cuboid : entry.getValue()) { + writeVarInt(cuboid.getOrigin().getBlockX(), bytes); + writeVarInt(cuboid.getOrigin().getBlockY(), bytes); + writeVarInt(cuboid.getOrigin().getBlockZ(), bytes); + if (cuboid.getSize().equals(BlockVector3.ONE)) { + writeVarInt(0, bytes); + } else if (cuboid.getSize().getBlockX() == cuboid.getSize().getBlockY() && cuboid.getSize().getBlockX() == cuboid.getSize().getBlockZ()) { + writeVarInt(cuboid.getSize().getBlockX(), bytes); + writeVarInt(0, bytes); + } else { + writeVarInt(cuboid.getSize().getBlockX(), bytes); + writeVarInt(cuboid.getSize().getBlockY(), bytes); + writeVarInt(cuboid.getSize().getBlockZ(), bytes); + } + } + byte[] bytesArray = new byte[bytes.size()]; + for (int i = 0; i < bytesArray.length; i++) { + bytesArray[i] = bytes.get(i); + } + cuboidBytes.put(entry.getKey(), bytesArray); + + if (mostBytes == null || bytesArray.length > mostBytesSize) { + mostBytes = entry.getKey(); + mostBytesSize = bytesArray.length; + } + } + System.out.println("Most bytes: " + mostBytes.getAsString() + " (" + mostBytesSize + " bytes)"); + cuboidBytes.remove(mostBytes); + out1.writeNamedTag("BASE", mostBytes.getAsString()); + for (Map.Entry entry : cuboidBytes.entrySet()) { + out1.writeLazyCompoundTag(entry.getKey().getAsString().substring(10), out2 -> { + out2.writeTagPayload(new ByteArrayTag(entry.getValue())); + }); + } + }); + }); + } + + private static void writeVarInt(int value, List bytes) { + while (true) { + if (value < 128) { + bytes.add((byte) value); + return; + } else { + bytes.add((byte) (value & 127 | 128)); + value >>>= 7; + } + } + } + + @Override + public void close() throws IOException { + outputStream.close(); + } +}