diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java index 52743811..0de6c6c5 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java +++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java @@ -28,12 +28,15 @@ import java.sql.PreparedStatement; import java.util.zip.GZIPInputStream; @AllArgsConstructor +@Getter public class NodeData { static { new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); + + SqlTypeMapper.ordinalEnumMapper(SchematicFormat.class); } private static final Table table = new Table<>(NodeData.class); @@ -48,19 +51,18 @@ public class NodeData { throw new IllegalArgumentException("Node is a directory"); return get.select(rs -> { if(rs.next()) { - return new NodeData(node.getId(), rs.getBoolean("NodeFormat")); + return new NodeData(node.getId(), SchematicFormat.values()[rs.getInt("NodeFormat")]); } else { - return new NodeData(node.getId(), false); + return new NodeData(node.getId(), SchematicFormat.MCEDIT); } }, node); } - @Getter @Field(keys = {Table.PRIMARY}) private final int nodeId; @Field - private boolean nodeFormat; + private SchematicFormat nodeFormat; public InputStream schemData() throws IOException { try { @@ -81,12 +83,18 @@ public class NodeData { } } - public void saveFromStream(InputStream blob, boolean newFormat) { + public void saveFromStream(InputStream blob, SchematicFormat newFormat) { updateDatabase.update(nodeId, newFormat, blob); nodeFormat = newFormat; } - public boolean getNodeFormat() { - return nodeFormat; + @AllArgsConstructor + @Getter + public enum SchematicFormat { + MCEDIT(".schematic"), + SPONGE_V2(".schem"), + SPONGE_V3(".schem"); + + private final String fileEnding; } } diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java index 3df740da..bece8549 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java @@ -375,11 +375,10 @@ public class SchematicNode { return nodeType == null; } - @Deprecated - public boolean getSchemFormat() { + public String getFileEnding() { if(isDir()) throw new SecurityException("Node is Directory"); - return NodeData.get(this).getNodeFormat(); + return NodeData.get(this).getNodeFormat().getFileEnding(); } public int getRank() { diff --git a/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java b/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java index 288b89e8..9a0ae4b5 100644 --- a/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java +++ b/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java @@ -42,6 +42,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import org.bukkit.DyeColor; @@ -144,6 +145,6 @@ public class WorldeditWrapper14 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), true); + new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2); } } diff --git a/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java b/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java index 19854db8..018552f2 100644 --- a/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java +++ b/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java @@ -39,6 +39,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.World; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import org.bukkit.DyeColor; @@ -142,6 +143,6 @@ public class WorldeditWrapper8 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), false); + new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index 825c5eb6..47efc09d 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -22,6 +22,7 @@ package de.steamwar.fightsystem.record; import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.core.Core; import de.steamwar.core.TrickyTrialsWrapper; +import de.steamwar.core.WorldEditWrapper; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.entity.RPlayer; @@ -523,7 +524,7 @@ public class PacketProcessor implements Listener { public void close() { // FAWE 1.12 calls close... } - }, Core.getVersion() > 12); + }, WorldEditWrapper.impl.getNativeFormat()); execSync(() -> team.pasteSchem(schemId, clipboard)); } diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java index 2b953b74..860435b9 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java @@ -245,7 +245,7 @@ public class SchematicCommandUtils { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_ELO", player, node.getElo(Season.getSeason())); } - SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getSchemFormat() ? ".schem" : ".schematic"); + SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getFileEnding()); CheckedSchematic.getLastDeclinedOfNode(node.getId()).stream().findFirst().ifPresent(checkedSchematic -> SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_STATUS", player, checkedSchematic.getEndTime(), checkedSchematic.getDeclineReason())); } else { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_TYPE", player, SchematicSystem.MESSAGE.parse("UTIL_INFO_TYPE_DIR", player)); diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index cd116bac..6f5d0ffc 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -22,7 +22,6 @@ package de.steamwar.core; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.sk89q.jnbt.*; -import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -45,36 +44,29 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import de.steamwar.sql.NoClipboardException; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.io.*; import java.util.*; -import java.util.logging.Level; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; public class WorldEditWrapper14 implements WorldEditWrapper { - private static final ClipboardFormat SCHEMATIC = BuiltInClipboardFormat.MCEDIT_SCHEMATIC; - private static final ClipboardFormat SCHEM = BuiltInClipboardFormat.SPONGE_SCHEMATIC; - @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> { - if(schemFormat){ - ClipboardWriter writer = SCHEM.getWriter(outputStream); - writer.write(clipboard); - writer.close(); - }else{ - SCHEMATIC.getWriter(outputStream).write(clipboard); - } + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> { + ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(outputStream); + writer.write(clipboard); + writer.close(); }); } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { Clipboard clipboard = null; try { clipboard = getClipboard(is, schemFormat); @@ -90,12 +82,17 @@ public class WorldEditWrapper14 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { try { - if(schemFormat){ - return new SpongeSchematicReader(new NBTInputStream(is)).read(); - }else{ - return new MCEditSchematicReader(new NBTInputStream(is)).read(); + + switch (schemFormat) { + case SPONGE_V2: + case SPONGE_V3: + return new SpongeSchematicReader(new NBTInputStream(is)).read(); + case MCEDIT: + return new MCEditSchematicReader(new NBTInputStream(is)).read(); + default: + throw new IOException("This schematic format is currently not supported"); } } catch (NullPointerException e) { throw new NoClipboardException(); @@ -124,6 +121,11 @@ public class WorldEditWrapper14 implements WorldEditWrapper { return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ()); } + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.SPONGE_V2; + } + private static class MCEditSchematicReader extends NBTSchematicReader { private final NBTInputStream inputStream; @@ -387,7 +389,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { inputStream.close(); } } - private static class SpongeSchematicReader extends NBTSchematicReader { + public static class SpongeSchematicReader extends NBTSchematicReader { private final NBTInputStream inputStream; private DataFixer fixer = null; @@ -418,7 +420,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1- fixer = platform.getDataFixer(); return readVersion1(schematicTag); - } else if (schematicVersion == 2) { + } else if (schematicVersion == 2 || schematicVersion == 3) { dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); if (dataVersion < liveDataVersion) { fixer = platform.getDataFixer(); @@ -447,14 +449,18 @@ public class WorldEditWrapper14 implements WorldEditWrapper { private CompoundTag getBaseTag() throws IOException { NamedTag rootTag = inputStream.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { - throw new IOException("Tag 'Schematic' does not exist or is not first"); - } CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check Map schematic = schematicTag.getValue(); + if (schematic.size() == 1) { + schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); + schematic = schematicTag.getValue(); + } else if (!rootTag.getName().equals("Schematic")) { + throw new IOException("Tag 'Schematic' does not exist or is not first"); + } + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); return schematicTag; } @@ -499,12 +505,16 @@ public class WorldEditWrapper14 implements WorldEditWrapper { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); } - IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { - throw new IOException("Block palette size does not match expected size."); + Map blockContainer = null; + boolean v3Mode = false; + + if (schematicVersion == 3) { + blockContainer = requireTag(schematic, "Blocks", CompoundTag.class).getValue(); + v3Mode = true; } + Map paletteObject = requireTag(v3Mode ? blockContainer: schematic, "Palette", CompoundTag.class).getValue(); + Map palette = new HashMap<>(); ParserContext parserContext = new ParserContext(); @@ -526,12 +536,12 @@ public class WorldEditWrapper14 implements WorldEditWrapper { palette.put(id, state); } - byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + byte[] blocks = requireTag(v3Mode ? blockContainer: schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + ListTag tileEntities = getTag(v3Mode ? blockContainer: schematic, "BlockEntities", ListTag.class); if (tileEntities == null) { - tileEntities = getTag(schematic, "TileEntities", ListTag.class); + tileEntities = getTag(v3Mode ? blockContainer: schematic, "TileEntities", ListTag.class); } if (tileEntities != null) { List> tileEntityTags = tileEntities.getValue().stream() diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java index 903113c4..1c674150 100644 --- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java +++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java @@ -23,6 +23,7 @@ import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; import de.steamwar.sql.NoClipboardException; +import de.steamwar.sql.NodeData; import java.io.IOException; import java.io.InputStream; @@ -31,11 +32,19 @@ public class WorldEditWrapper18 extends WorldEditWrapper14 { @Override @SuppressWarnings("removal") - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { NBTInputStream nbtStream = new NBTInputStream(is); //Use FAWE reader due to FAWE capability of reading corrupt FAWE schems try { - return (schemFormat ? new SpongeSchematicReader(nbtStream) : new MCEditSchematicReader(nbtStream)).read(); + switch (schemFormat) { + case MCEDIT: + return new MCEditSchematicReader(nbtStream).read(); + case SPONGE_V2: + case SPONGE_V3: + return new WorldEditWrapper14.SpongeSchematicReader(nbtStream).read(); + default: + throw new IllegalArgumentException("Unsupported schematic format"); + } } catch (NullPointerException e) { throw new NoClipboardException(); } diff --git a/SpigotCore/SpigotCore_21/build.gradle.kts b/SpigotCore/SpigotCore_21/build.gradle.kts index b9a7805e..8f2acba4 100644 --- a/SpigotCore/SpigotCore_21/build.gradle.kts +++ b/SpigotCore/SpigotCore_21/build.gradle.kts @@ -21,7 +21,13 @@ plugins { steamwar.java } +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + dependencies { + compileOnly(project(":CommonCore", "default")) compileOnly(project(":SpigotCore:SpigotCore_Main", "default")) compileOnly(project(":SpigotCore:SpigotCore_18", "default")) compileOnly(project(":SpigotCore:SpigotCore_14", "default")) @@ -29,16 +35,6 @@ dependencies { compileOnly(libs.fawe21) - compileOnly(libs.paperapi21) { - attributes { - // Very Hacky, but it works - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) - } - } - compileOnly(libs.nms21) { - attributes { - // Very Hacky, but it works - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) - } - } + compileOnly(libs.paperapi21) + compileOnly(libs.nms21) } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index 4ae22cac..d93c095d 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -20,33 +20,30 @@ package de.steamwar.core; import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; -import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.enginehub.linbus.stream.LinBinaryIO; -import org.enginehub.linbus.stream.LinStream; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinRootEntry; -import org.enginehub.linbus.tree.LinTagType; import java.io.*; public class WorldEditWrapper21 implements WorldEditWrapper { @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> { + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> { ClipboardWriter writer = BuiltInClipboardFormat.FAST_V3.getWriter(outputStream); writer.write(clipboard); writer.close(); @@ -54,7 +51,7 @@ public class WorldEditWrapper21 implements WorldEditWrapper { } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { Clipboard clipboard = null; try { clipboard = getClipboard(is, schemFormat); @@ -70,35 +67,12 @@ public class WorldEditWrapper21 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { - if (!schemFormat) { - return new MCEditSchematicReader(new NBTInputStream(is)).read(); - } else { - BufferedInputStream bis = new BufferedInputStream(is); - - bis.mark(Integer.MAX_VALUE); - - LinStream linStream = LinBinaryIO.read(new DataInputStream(bis)); - - LinCompoundTag entry = LinRootEntry.readFrom(linStream).value(); - - if (entry.value().size() == 1) { - entry = entry.getTag("Schematic", LinTagType.compoundTag()); - } - - bis.reset(); - - switch (entry.getTag("Version", LinTagType.intTag()).valueAsInt()) { - case 1: - return new SpongeSchematicV1Reader(entry.linStream()).read(); - case 2: - return new FastSchematicReaderV2(new NBTInputStream(bis)).read(); - case 3: - return new FastSchematicReaderV3(bis).read(); - default: - throw new IOException("Unknown schematic version"); - } - } + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { + return switch (schemFormat) { + case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); + case SPONGE_V2 -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(is))).read(); + case SPONGE_V3 -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(is))).read(); + }; } @Override @@ -122,4 +96,9 @@ public class WorldEditWrapper21 implements WorldEditWrapper { v = transform.apply(v); return new org.bukkit.util.Vector(v.x(), v.y(), v.z()); } + + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.SPONGE_V3; + } } diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java index f3fc2800..75957933 100644 --- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java @@ -37,6 +37,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import java.io.IOException; @@ -50,13 +51,13 @@ import java.util.stream.Collectors; public class WorldEditWrapper8 implements WorldEditWrapper { @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData())); } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { WorldData world = new BukkitWorld(player.getWorld()).getWorldData(); Clipboard clipboard; try { @@ -70,11 +71,16 @@ public class WorldEditWrapper8 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { - if(schemFormat) - return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); - else - return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { + switch (schemFormat) { + case MCEDIT: + return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + case SPONGE_V2: + case SPONGE_V3: + return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + default: + throw new IllegalArgumentException("Unsupported schematic format"); + } } @Override @@ -99,6 +105,11 @@ public class WorldEditWrapper8 implements WorldEditWrapper { return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ()); } + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.MCEDIT; + } + private static class SpongeSchematicReader implements ClipboardReader { private final NBTInputStream inputStream; @@ -137,6 +148,13 @@ public class WorldEditWrapper8 implements WorldEditWrapper { IDConverter8 ids = new IDConverter8(); Map schematic = schematicTag.getValue(); + boolean v3Mode = false; + + if (schematic.size() == 1) { + schematic = (requireTag(schematic, "Schematic", CompoundTag.class)).getValue(); + v3Mode = true; + } + int width = (requireTag(schematic, "Width", ShortTag.class)).getValue(); int height = (requireTag(schematic, "Height", ShortTag.class)).getValue(); int length = (requireTag(schematic, "Length", ShortTag.class)).getValue(); @@ -167,10 +185,13 @@ public class WorldEditWrapper8 implements WorldEditWrapper { region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector.ONE)); } - IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) - throw new IOException("Block palette size does not match expected size."); + Map blockContainer = null; + + if (v3Mode) { + blockContainer = getTag(schematic, "Blocks", CompoundTag.class).getValue(); + } + + Map paletteObject = requireTag(v3Mode ? blockContainer : schematic, "Palette", CompoundTag.class).getValue(); Map palette = new HashMap<>(); ParserContext parserContext = new ParserContext(); @@ -182,11 +203,11 @@ public class WorldEditWrapper8 implements WorldEditWrapper { palette.put(requireTag(paletteObject, palettePart, IntTag.class).getValue(), new BaseBlock(blockID.getBlockId(), blockID.getDataId())); } - byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + byte[] blocks = requireTag(v3Mode ? blockContainer : schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + ListTag tileEntities = getTag(v3Mode ? blockContainer : schematic, "BlockEntities", ListTag.class); if (tileEntities == null) { - tileEntities = getTag(schematic, "TileEntities", ListTag.class); + tileEntities = getTag(v3Mode ? blockContainer : schematic, "TileEntities", ListTag.class); } if (tileEntities != null) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java index 87906944..9928b947 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import de.steamwar.sql.NoClipboardException; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; +import de.steamwar.sql.NodeData; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -36,20 +37,22 @@ import java.util.logging.Level; public interface WorldEditWrapper { WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); - InputStream getPlayerClipboard(Player player, boolean schemFormat); - void setPlayerClipboard(Player player, InputStream is, boolean schemFormat); - Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException; + InputStream getPlayerClipboard(Player player); + void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat); + Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException; Vector getOrigin(Clipboard clipboard); Vector getMinimum(Region region); Vector getMaximum(Region region); Vector applyTransform(Vector vector, Transform transform); + NodeData.SchematicFormat getNativeFormat(); + static WorldEditPlugin getWorldEditPlugin() { return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); } - public static InputStream getPlayerClipboard(Player player, boolean schemFormat, SchematicWriter consumer) { + static InputStream getPlayerClipboard(Player player, SchematicWriter consumer) { ClipboardHolder clipboardHolder; try { clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard(); @@ -85,7 +88,7 @@ public interface WorldEditWrapper { return inputStream; } - public static interface SchematicWriter { + interface SchematicWriter { void write(OutputStream outputStream, Clipboard clipboard, ClipboardHolder holder) throws IOException; } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index ecbf86aa..62f00369 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -36,7 +36,7 @@ import java.util.zip.GZIPInputStream; public class SchematicData { - public static Clipboard clipboardFromStream(InputStream is, boolean schemFormat) { + public static Clipboard clipboardFromStream(InputStream is, NodeData.SchematicFormat schemFormat) { try { return WorldEditWrapper.impl.getClipboard(is, schemFormat); } catch (IOException e) { @@ -61,15 +61,11 @@ public class SchematicData { } public void saveFromPlayer(Player player) throws IOException, NoClipboardException { - saveFromPlayer(player, Core.getVersion() > 12); - } - - public void saveFromPlayer(Player player, boolean newFormat) throws IOException, NoClipboardException { - data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player, newFormat), newFormat); + data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat()); } @Deprecated - public void saveFromBytes(byte[] bytes, boolean newFormat) { + public void saveFromBytes(byte[] bytes, NodeData.SchematicFormat newFormat) { data.saveFromStream(new ByteArrayInputStream(bytes), newFormat); } } diff --git a/SpigotCore/build.gradle.kts b/SpigotCore/build.gradle.kts index b7ff647e..d615cfc7 100644 --- a/SpigotCore/build.gradle.kts +++ b/SpigotCore/build.gradle.kts @@ -40,5 +40,10 @@ dependencies { implementation(project(":SpigotCore:SpigotCore_18")) implementation(project(":SpigotCore:SpigotCore_19")) implementation(project(":SpigotCore:SpigotCore_20")) - implementation(project(":SpigotCore:SpigotCore_21")) + implementation(project(":SpigotCore:SpigotCore_21")) { + attributes { + // Very Hacky, but it works + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) + } + } } diff --git a/VelocityCore/build.gradle.kts b/VelocityCore/build.gradle.kts index 78603f8c..d3480ca8 100644 --- a/VelocityCore/build.gradle.kts +++ b/VelocityCore/build.gradle.kts @@ -63,4 +63,6 @@ dependencies { implementation(libs.msgpack) implementation(libs.apolloprotos) + + implementation(libs.nbt) } \ No newline at end of file diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java index 037eadcd..68b8d360 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java @@ -25,10 +25,13 @@ import de.steamwar.sql.NodeData; import de.steamwar.sql.Punishment; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; +import dev.dewy.nbt.Nbt; +import dev.dewy.nbt.tags.collection.CompoundTag; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -38,6 +41,8 @@ import java.util.logging.Level; public class DiscordSchemUpload extends ListenerAdapter { + private static final Nbt NBT = new Nbt(); + private static final List SCHEM_FILE_ENDINGS = Arrays.asList(".schem", ".schematic"); @Override @@ -79,7 +84,17 @@ public class DiscordSchemUpload extends ListenerAdapter { node = SchematicNode.createSchematic(user.getId(), name, null); try (InputStream in = attachment.getProxy().download().get()) { - NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem")); + CompoundTag tags = NBT.fromStream(new DataInputStream(in)); + + NodeData.SchematicFormat version = NodeData.SchematicFormat.SPONGE_V2; + + if (tags.size() == 1) { + version = NodeData.SchematicFormat.SPONGE_V3; + } else if (tags.contains("Materials")) { + version = NodeData.SchematicFormat.MCEDIT; + } + + NodeData.get(node).saveFromStream(in, version); sender.system("DC_SCHEMUPLOAD_SUCCESS", name); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/WebsiteBackend/build.gradle.kts b/WebsiteBackend/build.gradle.kts index 2cf527a7..d58a5142 100644 --- a/WebsiteBackend/build.gradle.kts +++ b/WebsiteBackend/build.gradle.kts @@ -53,4 +53,5 @@ dependencies { implementation(libs.yamlconfig) implementation(libs.kotlinxSerializationCbor) implementation(libs.ktorRateLimit) + implementation(libs.nbt) } \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index b873b97d..c4d76f80 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -22,10 +22,13 @@ package de.steamwar.routes import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.NodeData +import de.steamwar.sql.NodeData.SchematicFormat import de.steamwar.sql.NodeDownload import de.steamwar.sql.NodeMember import de.steamwar.sql.SWException import de.steamwar.sql.SchematicNode +import dev.dewy.nbt.Nbt +import dev.dewy.nbt.tags.collection.CompoundTag import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* @@ -33,6 +36,7 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromByteArray import java.security.MessageDigest import java.time.Duration import java.time.Instant @@ -71,6 +75,8 @@ data class SchematicCode(val id: Int, val code: String, val expires: Long) @Serializable data class UploadSchematic(val name: String, val content: String) +val nbt = Nbt() + fun Route.configureSchematic() { route("/download/{code}") { get { @@ -88,7 +94,7 @@ fun Route.configureSchematic() { return@get } - call.response.header("Content-Disposition", "attachment; filename=\"${node.name}.${if (data.nodeFormat) "schem" else "schematic"}\"") + call.response.header("Content-Disposition", "attachment; filename=\"${node.name}${data.nodeFormat.fileEnding}\"") call.respondBytes(data.schemData().readAllBytes(), contentType = ContentType.Application.OctetStream, status = HttpStatusCode.OK) } get("/info") { @@ -112,16 +118,34 @@ fun Route.configureSchematic() { val user = call.principal()!!.user - val content = Base64.getDecoder().decode(file.content) var node = SchematicNode.getSchematicNode(user.id, schemName, 0) if (node == null) { node = SchematicNode.createSchematic(user.id, schemName, 0) } - val data = NodeData(node.id, false) - data.saveFromStream(content.inputStream(), schemType == "schem") + try { + val content = Base64.getDecoder().decode(file.content) - call.respond(ResponseSchematic(node)) + var schem = nbt.fromByteArray(content) + + if (schem.size() == 1) schem = schem.first() as CompoundTag + + val version = schem.let { + if (it.contains("Materials")) + return@let SchematicFormat.MCEDIT + else if (it.contains("Blocks")) + return@let SchematicFormat.SPONGE_V3 + else + return@let SchematicFormat.SPONGE_V2 + } + + val data = NodeData(node.id, version) + data.saveFromStream(content.inputStream(), version) + + call.respond(ResponseSchematic(node)) + } catch (e: Exception) { + call.respond(HttpStatusCode.BadRequest) + } } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index a29c0412..8f3fcdcb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -164,6 +164,8 @@ dependencyResolutionManagement { library("yamlconfig", "org.bspfsystems:yamlconfiguration:1.3.0") library("kotlinxSerializationCbor", "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.4.1") library("ktorRateLimit", "io.ktor:ktor-server-rate-limit:$ktorVersion") + + library("nbt", "dev.dewy:nbt:1.5.1") } } }