diff --git a/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java b/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java index bed0e3f..71afd1d 100644 --- a/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java +++ b/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java @@ -10,6 +10,7 @@ import io.ib67.sfcraft.module.compat.ModCompatModule; import io.ib67.sfcraft.module.randomevt.LongNightModule; import io.ib67.sfcraft.module.room.CreativeRoomModule; +import io.ib67.sfcraft.module.supervisor.WebModule; import io.ib67.sfcraft.registry.RoomRegistry; import io.ib67.sfcraft.registry.chat.SimpleMessageDecorator; import io.ib67.sfcraft.registry.event.SFRandomEventRegistry; @@ -65,7 +66,7 @@ private void registerFeatures() { registerFeature(CreativeRoomModule.class); registerFeature(ChatPrefixModule.class); registerFeature(CustomItemModule.class); - + registerFeature(WebModule.class); } @Override diff --git a/src/main/java/io/ib67/sfcraft/module/supervisor/WebModule.java b/src/main/java/io/ib67/sfcraft/module/supervisor/WebModule.java index ab7eddc..e07a8e9 100644 --- a/src/main/java/io/ib67/sfcraft/module/supervisor/WebModule.java +++ b/src/main/java/io/ib67/sfcraft/module/supervisor/WebModule.java @@ -17,6 +17,8 @@ import net.minecraft.nbt.NbtSizeTracker; 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.Path; @@ -33,29 +35,36 @@ public class WebModule extends ServerModule { SFConfig config; @Inject SignatureService signatureService; + private Javalin javalin; @Override @SneakyThrows public void onInitialize() { Files.createDirectories(SCHEMATIC_DIR); + javalin = Javalin.create(cfg -> cfg.useVirtualThreads = false) + .put("/api/schematics", this::uploadSchematic); Thread.ofVirtual().name("SFCraft API Web").start(() -> { - Javalin.create(cfg -> cfg.useVirtualThreads = true) - .put("/api/schematics", this::uploadSchematic) - .start(config.httpPort); + javalin.start(config.httpPort); }); } + @Override + public void onDisable() { + javalin.stop(); + } + private void uploadSchematic(@NotNull Context context) { if (context.contentLength() > config.maxSchematicSize) { context.result("Content is too large!"); return; } - var signRaw = Base64.getUrlDecoder().decode(context.pathParam("sign")); - var verifiedSign = signatureService.readSignature(Unpooled.wrappedBuffer(signRaw)); - if ((verifiedSign.permission() & PERMISSION_UPLOAD_SCHEMATICS) == 0) { - context.result("Permission denied!"); - return; - } + +// var signRaw = Base64.getUrlDecoder().decode(context.pathParam("sign")); +// var verifiedSign = signatureService.readSignature(Unpooled.wrappedBuffer(signRaw)); +// if ((verifiedSign.permission() & PERMISSION_UPLOAD_SCHEMATICS) == 0) { +// context.result("Permission denied!"); +// return; +// } var files = context.uploadedFileMap(); files.forEach((k, v) -> handleUploadSchematic(context, k, v)); } @@ -70,27 +79,33 @@ private void handleUploadSchematic(@NotNull Context context, String fileName, Li context.result("Content is too large!"); return; } - fileName = Helper.cleanFileName(fileName); + if (fileName.length() <= 10) return; + var baseFileName = Helper.cleanFileName(fileName.substring(0, fileName.length() - 10)); + log.info("Handling new file: {}", fileName); if (fileName.endsWith(".schematic")) { - Files.write(SCHEMATIC_DIR.resolve(fileName), file.content().readAllBytes()); - file.content().close(); - log.info("Saved "+fileName+" as a schematic."); - context.result("Success!"); + Files.write(SCHEMATIC_DIR.resolve(baseFileName+".schematic"), file.content().readAllBytes()); + log.info("Saved " + fileName + " as a schematic."); } else if (fileName.endsWith(".litematic")) { log.error("Handling new {}", fileName); - var baseFileName = fileName.substring(0, fileName.length() - 10); - new LitematicConverter( + var converter = new LitematicConverter( file.content(), new NbtSizeTracker(config.maxSchematicSize, 16) - ).read((name, nbt) -> { - name = Helper.cleanFileName(baseFileName + "-" + name + ".schematic"); - try { - NbtIo.writeCompressed(nbt, SCHEMATIC_DIR.resolve(name)); - log.info("Schematic" + name+" has been saved!"); - } catch (IOException e) { - log.error("Error occurred when serializing .schematic from .litematic.", e); - } - }); + ); + try { + converter.read((name, nbt) -> { + name = baseFileName + "-" + name + ".schematic"; + try { + NbtIo.writeCompressed(nbt, SCHEMATIC_DIR.resolve(name)); + log.info("Schematic " + name + " has been saved!"); + context.result("Success!"); + } catch (Exception e) { + log.error("Error occurred when serializing .litematic to disk.", e); + } + }); + } catch (Exception e) { + log.error("Error occurred when converting .litematic.", e); + } + converter.close(); } } } diff --git a/src/main/java/io/ib67/sfcraft/util/LitematicConverter.java b/src/main/java/io/ib67/sfcraft/util/LitematicConverter.java index d719091..b43de6a 100644 --- a/src/main/java/io/ib67/sfcraft/util/LitematicConverter.java +++ b/src/main/java/io/ib67/sfcraft/util/LitematicConverter.java @@ -17,7 +17,6 @@ * Uses {@link NbtCompound} from Minecraft. */ public class LitematicConverter implements AutoCloseable { - public static final String NBT_LITEMATICA_ROOT = ""; private final InputStream input; private final NbtSizeTracker sizeTracker; @@ -30,7 +29,7 @@ public LitematicConverter(InputStream input, NbtSizeTracker sizeTracker) { public void read( BiConsumer schematicOutput ) { - var root = NbtIo.readCompressed(input, sizeTracker).getCompound(NBT_LITEMATICA_ROOT); + var root = NbtIo.readCompressed(input, sizeTracker); var dataVersion = root.getInt("MinecraftDataVersion"); var regionsNbt = root.getCompound("Regions"); var i = 0; @@ -64,7 +63,7 @@ private NbtCompound convertRegionToSchematic(int dataVersion, NbtCompound region worldEditTag.put("BlockEntities", convertToWETileEntities(tileEntities)); worldEditTag.putInt("Version", 2); worldEditTag.putIntArray("Offset", new int[3]); - worldEditTag.putByteArray("BlockData", convertToWEBlocks(size.x * size.y * size.z, region)); + worldEditTag.putByteArray("BlockData", convertToWEBlocks(Math.abs(size.x * size.y * size.z), region)); var schematicsRoot = new NbtCompound(); schematicsRoot.put("Schematic", worldEditTag); return schematicsRoot; @@ -121,9 +120,9 @@ private NbtCompound convertToWEPalette(NbtList paletteNbt) { private NbtElement convertToWeMeta(SizeTuple size, NbtCompound region) { var pos = (NbtCompound) region.get("Position"); var nbt = new NbtCompound(); - nbt.putInt("WEOffsetX", pos.getInt("x") + size.x < 0 ? size.x + 1 : 0); - nbt.putInt("WEOffsetY", pos.getInt("y") + size.y < 0 ? size.y + 1 : 0); - nbt.putInt("WEOffsetZ", pos.getInt("z") + size.z < 0 ? size.z + 1 : 0); + nbt.putInt("WEOffsetX", pos.getInt("x") + (size.x < 0 ? size.x + 1 : 0)); + nbt.putInt("WEOffsetY", pos.getInt("y") + (size.y < 0 ? size.y + 1 : 0)); + nbt.putInt("WEOffsetZ", pos.getInt("z") + (size.z < 0 ? size.z + 1 : 0)); return nbt; } @@ -132,14 +131,14 @@ private byte[] convertToWEBlocks(int totalBlocks, NbtCompound region) { var blockStates = region.getLongArray("BlockStates"); int bitsPerBlock = region.getList("BlockStatePalette", NbtElement.COMPOUND_TYPE).size(); - bitsPerBlock = Math.max(2, Integer.SIZE - Integer.numberOfTrailingZeros(bitsPerBlock - 1)); + bitsPerBlock = Math.max(2, Integer.SIZE - Integer.numberOfLeadingZeros(bitsPerBlock - 1)); int bitCounts = 0, blockIterated = 0; long bitMask, bits = 0; for (long blockState : blockStates) { int remainingBits = bitCounts + 64; if (bitCounts != 0) { - bitMask = (1L << (bitsPerBlock - bitCounts)) - 1; + bitMask = (1 << (bitsPerBlock - bitCounts)) - 1; long newBits = (blockState & bitMask) << bitCounts; bits = bits | newBits; blockState = blockState >>> (bitsPerBlock - bitCounts); @@ -148,7 +147,7 @@ private byte[] convertToWEBlocks(int totalBlocks, NbtCompound region) { blockIterated++; } - bitMask = (1L << bitsPerBlock) - 1; + bitMask = (1 << bitsPerBlock) - 1; while(remainingBits >= bitsPerBlock){ bits = blockState & bitMask; blockState = blockState >>> bitsPerBlock;