Add support for schematics v3 output <3

This commit is contained in:
iceBear67 committed 2025-01-06 21:55:46 +08:00
1 parent a7204cceb7
commit 95ed2a8a85
3 files changed
+81 -27

No files matched your search

@@ -5,27 +5,20 @@ import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.module.SignatureService; import io.ib67.sfcraft.module.SignatureService;
import io.ib67.sfcraft.util.Helper; import io.ib67.sfcraft.util.Helper;
import io.ib67.sfcraft.util.LitematicConverter; import io.ib67.sfcraft.util.litematic.LitematicConverter;
import io.ib67.sfcraft.util.litematic.LitematicConverterV3;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.http.Context; import io.javalin.http.Context;
import io.javalin.http.UploadedFile; import io.javalin.http.UploadedFile;
import io.netty.buffer.Unpooled;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.nbt.NbtSizeTracker;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.regex.Pattern;
@Log4j2 @Log4j2
public class WebModule extends ServerModule { public class WebModule extends ServerModule {
@@ -87,7 +80,7 @@ public class WebModule extends ServerModule {
log.info("Saved " + fileName + " as a schematic."); log.info("Saved " + fileName + " as a schematic.");
} else if (fileName.endsWith(".litematic")) { } else if (fileName.endsWith(".litematic")) {
log.error("Handling new {}", fileName); log.error("Handling new {}", fileName);
var converter = new LitematicConverter( var converter = new LitematicConverterV3(
file.content(), file.content(),
new NbtSizeTracker(config.maxSchematicSize, 16) new NbtSizeTracker(config.maxSchematicSize, 16)
); );
@@ -1,4 +1,4 @@
package io.ib67.sfcraft.util; package io.ib67.sfcraft.util.litematic;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -6,8 +6,6 @@ import lombok.SneakyThrows;
import net.minecraft.nbt.*; import net.minecraft.nbt.*;
import java.io.InputStream; import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -17,8 +15,8 @@ import java.util.stream.Collectors;
* Uses {@link NbtCompound} from Minecraft. * Uses {@link NbtCompound} from Minecraft.
*/ */
public class LitematicConverter implements AutoCloseable { public class LitematicConverter implements AutoCloseable {
private final InputStream input; protected final InputStream input;
private final NbtSizeTracker sizeTracker; protected final NbtSizeTracker sizeTracker;
public LitematicConverter(InputStream input, NbtSizeTracker sizeTracker) { public LitematicConverter(InputStream input, NbtSizeTracker sizeTracker) {
this.input = input; this.input = input;
@@ -41,7 +39,7 @@ public class LitematicConverter implements AutoCloseable {
} }
} }
private NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region) { protected NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region) {
var worldEditTag = new NbtCompound(); var worldEditTag = new NbtCompound();
// prepare metadata // prepare metadata
@@ -69,7 +67,7 @@ public class LitematicConverter implements AutoCloseable {
return schematicsRoot; return schematicsRoot;
} }
private SizeTuple readSizeTuple(NbtCompound region) { protected SizeTuple readSizeTuple(NbtCompound region) {
var size = (NbtCompound) region.get("Size"); var size = (NbtCompound) region.get("Size");
var sizeX = size.getInt("x"); var sizeX = size.getInt("x");
var sizeY = size.getInt("y"); var sizeY = size.getInt("y");
@@ -77,27 +75,29 @@ public class LitematicConverter implements AutoCloseable {
return new SizeTuple(sizeX, sizeY, sizeZ); return new SizeTuple(sizeX, sizeY, sizeZ);
} }
private NbtList convertToWETileEntities(NbtList tileEntities) { protected NbtList convertToWETileEntities(NbtList tileEntities) {
var weTEs = new NbtList(); var weTEs = new NbtList();
for (NbtElement _tileEntity : tileEntities) { for (NbtElement _tileEntity : tileEntities) {
var weTE = new NbtCompound();
var tE = (NbtCompound) _tileEntity; var tE = (NbtCompound) _tileEntity;
tE.putIntArray("Pos", new int[]{ weTE.putIntArray("Pos", new int[]{
tE.getInt("x"), tE.getInt("x"),
tE.getInt("y"), tE.getInt("y"),
tE.getInt("z") tE.getInt("z")
}); });
tE.putString("Id", tE.getString("id")); weTE.putString("Id", tE.getString("id"));
// other properties // other properties
tE.remove("x"); tE.remove("x");
tE.remove("y"); tE.remove("y");
tE.remove("z"); tE.remove("z");
tE.remove("id"); tE.remove("id");
weTEs.add(tE); weTE.put("Data",tE);
weTEs.add(weTE);
} }
return weTEs; return weTEs;
} }
private NbtCompound convertToWEPalette(NbtList paletteNbt) { protected NbtCompound convertToWEPalette(NbtList paletteNbt) {
var wePalette = new NbtCompound(); var wePalette = new NbtCompound();
for (int i = 0; i < paletteNbt.size(); i++) { for (int i = 0; i < paletteNbt.size(); i++) {
var entry = (NbtCompound) paletteNbt.get(i); var entry = (NbtCompound) paletteNbt.get(i);
@@ -117,7 +117,7 @@ public class LitematicConverter implements AutoCloseable {
return wePalette; return wePalette;
} }
private NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) { protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position"); var pos = (NbtCompound) region.get("Position");
var nbt = new NbtCompound(); var nbt = new NbtCompound();
nbt.putInt("WEOffsetX", pos.getInt("x") + (size.x < 0 ? size.x + 1 : 0)); nbt.putInt("WEOffsetX", pos.getInt("x") + (size.x < 0 ? size.x + 1 : 0));
@@ -126,7 +126,7 @@ public class LitematicConverter implements AutoCloseable {
return nbt; return nbt;
} }
private byte[] convertToWEBlocks(int totalBlocks, NbtCompound region) { protected byte[] convertToWEBlocks(int totalBlocks, NbtCompound region) {
var buf = Unpooled.buffer(); var buf = Unpooled.buffer();
var blockStates = region.getLongArray("BlockStates"); var blockStates = region.getLongArray("BlockStates");
@@ -148,11 +148,11 @@ public class LitematicConverter implements AutoCloseable {
} }
bitMask = (1 << bitsPerBlock) - 1; bitMask = (1 << bitsPerBlock) - 1;
while(remainingBits >= bitsPerBlock){ while (remainingBits >= bitsPerBlock) {
bits = blockState & bitMask; bits = blockState & bitMask;
blockState = blockState >>> bitsPerBlock; blockState = blockState >>> bitsPerBlock;
remainingBits -= bitsPerBlock; remainingBits -= bitsPerBlock;
if(blockIterated >= totalBlocks) break; if (blockIterated >= totalBlocks) break;
writeBlocks(buf, (short) bits); writeBlocks(buf, (short) bits);
blockIterated++; blockIterated++;
} }
@@ -162,7 +162,7 @@ public class LitematicConverter implements AutoCloseable {
return buf.array(); return buf.array();
} }
private static int writeBlocks(ByteBuf buf, short block) { protected static int writeBlocks(ByteBuf buf, short block) {
int b = block >>> 7; int b = block >>> 7;
if (b == 0) { if (b == 0) {
buf.writeByte(block); buf.writeByte(block);
@@ -0,0 +1,61 @@
package io.ib67.sfcraft.util.litematic;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtSizeTracker;
import java.io.InputStream;
public class LitematicConverterV3 extends LitematicConverter {
public LitematicConverterV3(InputStream input, NbtSizeTracker sizeTracker) {
super(input, sizeTracker);
}
@Override
protected NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region) {
var schematicsTag = new NbtCompound();
// prepare metadata
var size = readSizeTuple(region);
schematicsTag.put("Metadata", convertToWeMeta(size, region));
schematicsTag.putInt("DataVersion", dataVersion);
schematicsTag.putInt("Version", 3);
schematicsTag.putIntArray("Offset", new int[3]);
// dimensional data.
schematicsTag.putShort("Height", (short) Math.abs(size.y()));
schematicsTag.putShort("Length", (short) Math.abs(size.z()));
schematicsTag.putShort("Width", (short) Math.abs(size.x()));
// block & tile entities
var paletteNbt = region.getList("BlockStatePalette", NbtElement.COMPOUND_TYPE);
var wePalette = convertToWEPalette(paletteNbt);
var tileEntities = region.getList("TileEntities", NbtElement.COMPOUND_TYPE);
var blocksNbt = new NbtCompound();
blocksNbt.put("Palette", wePalette);
blocksNbt.putByteArray("Data", convertToWEBlocks(Math.abs(size.x() * size.y() * size.z()), region));
blocksNbt.put("BlockEntities", convertToWETileEntities(tileEntities));
schematicsTag.put("Blocks", blocksNbt);
var schematicsRoot = new NbtCompound();
schematicsRoot.put("Schematic", schematicsTag);
return schematicsRoot;
}
@Override
protected NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) {
var pos = (NbtCompound) region.get("Position");
var worldEditNbt = new NbtCompound();
worldEditNbt.putIntArray("Origin", new int[]{
pos.getInt("x") + (size.x() < 0 ? size.x() + 1 : 0),
pos.getInt("y") + (size.y() < 0 ? size.y() + 1 : 0),
pos.getInt("z") + (size.z() < 0 ? size.z() + 1 : 0)
});
var Metadata = new NbtCompound();
Metadata.put("WorldEdit", worldEditNbt);
Metadata.putLong("Date", System.currentTimeMillis());
return Metadata;
}
}