From 841a097109347fafc4219fcb35092f46d03217b7 Mon Sep 17 00:00:00 2001 From: DartCZ Date: Sat, 11 Dec 2021 00:00:58 +0100 Subject: [PATCH] Added 1.17 entities storage import support (fixing #65) (#87) --- .../grinderwolf/swm/importer/SWMImporter.java | 70 +++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/slimeworldmanager-importer/src/main/java/com/grinderwolf/swm/importer/SWMImporter.java b/slimeworldmanager-importer/src/main/java/com/grinderwolf/swm/importer/SWMImporter.java index ed3b48c7..fbc3c15e 100644 --- a/slimeworldmanager-importer/src/main/java/com/grinderwolf/swm/importer/SWMImporter.java +++ b/slimeworldmanager-importer/src/main/java/com/grinderwolf/swm/importer/SWMImporter.java @@ -42,6 +42,7 @@ public class SWMImporter { private static final Pattern MAP_FILE_PATTERN = Pattern.compile("^(?:map_([0-9]*).dat)$"); private static final int SECTOR_SIZE = 4096; + private static boolean entityCustomStorage; public static void main(String[] args) { if (args.length == 0) { @@ -132,6 +133,14 @@ public static void importWorld(File worldFolder, File outputFile, boolean debug) throw new InvalidWorldException(worldFolder, "The world appears to be corrupted"); } + File entitiesDir = new File(worldFolder, "entities"); + + if(entitiesDir.exists()) { + entityCustomStorage = true; + + if(debug) System.out.println("Entities will be imported from custom storage (1.17 world or above)"); + } + if(debug) System.out.println("Loading world..."); File levelFile = new File(worldFolder, "level.dat"); @@ -171,7 +180,7 @@ public static void importWorld(File worldFolder, File outputFile, boolean debug) for (File file : regionDir.listFiles((dir, name) -> name.endsWith(".mca"))) { try { - chunks.addAll(loadChunks(file, worldVersion, debug)); + chunks.addAll(loadChunks(file, entitiesDir, worldVersion, debug)); } catch (IOException ex) { throw new IOException("Failed to read region file", ex); } @@ -248,7 +257,7 @@ private static CompoundTag loadMap(File mapFile) throws IOException { return tag; } - private static List loadChunks(File file, byte worldVersion, boolean debug) throws IOException { + private static List loadChunks(File file, File entitiesDir, byte worldVersion, boolean debug) throws IOException { if(debug) System.out.println("Loading chunks from region file '" + file.getName() + "':"); byte[] regionByteArray = Files.readAllBytes(file.toPath()); @@ -287,7 +296,12 @@ private static List loadChunks(File file, byte worldVersion, boolean CompoundTag levelCompound = (CompoundTag) globalMap.get("Level"); - return readChunk(levelCompound, worldVersion); + List entityList = null; + + if(entityCustomStorage) + entityList = readEntities(file, entitiesDir, entry.getOffset(), entry.getPaddedSize(), worldVersion, debug); + + return readChunk(levelCompound, entityList, worldVersion); } catch (IOException ex) { throw new RuntimeException(ex); } @@ -299,7 +313,46 @@ private static List loadChunks(File file, byte worldVersion, boolean return loadedChunks; } - private static SlimeChunk readChunk(CompoundTag compound, byte worldVersion) { + private static List readEntities(File regionFile, File entityDir, int offset, int paddedSize, byte worldVersion, boolean debug) throws IOException { + File file = new File(entityDir.getPath(), regionFile.getName()); + List entities = new ListTag("Entities", TagType.TAG_COMPOUND, new ArrayList<>()).getValue(); + + if(!file.exists()) { + return entities; + } + + if(debug) System.out.println("Loading chunk entities from region file '" + file.getName() + "':"); + + byte[] regionByteArray = Files.readAllBytes(file.toPath()); + + try { + DataInputStream headerStream = new DataInputStream(new ByteArrayInputStream(regionByteArray, offset, paddedSize)); + + if(headerStream.available() <= 0) { + return entities; + } + + int chunkSize = headerStream.readInt() - 1; + + int compressionScheme = headerStream.readByte(); + + DataInputStream chunkStream = new DataInputStream(new ByteArrayInputStream(regionByteArray, offset + 5, chunkSize)); + InputStream decompressorStream = compressionScheme == 1 ? new GZIPInputStream(chunkStream) : new InflaterInputStream(chunkStream); + NBTInputStream nbtStream = new NBTInputStream(decompressorStream, NBTInputStream.NO_COMPRESSION, ByteOrder.BIG_ENDIAN); + CompoundTag globalCompound = (CompoundTag) nbtStream.readTag(); + + entities = ((ListTag) globalCompound.getAsListTag("Entities") + .orElse(new ListTag<>("Entities", TagType.TAG_COMPOUND, new ArrayList<>()))).getValue(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + if(debug) System.out.println( entities.size() + " entities loaded at " + regionFile.getName()); + + return entities; + } + + private static SlimeChunk readChunk(CompoundTag compound, List entityList, byte worldVersion) { int chunkX = compound.getAsIntTag("xPos").get().getValue(); int chunkZ = compound.getAsIntTag("zPos").get().getValue(); Optional status = compound.getStringValue("Status"); @@ -336,8 +389,13 @@ private static SlimeChunk readChunk(CompoundTag compound, byte worldVersion) { List tileEntities = ((ListTag) compound.getAsListTag("TileEntities") .orElse(new ListTag<>("TileEntities", TagType.TAG_COMPOUND, new ArrayList<>()))).getValue(); - List entities = ((ListTag) compound.getAsListTag("Entities") - .orElse(new ListTag<>("Entities", TagType.TAG_COMPOUND, new ArrayList<>()))).getValue(); + List entities = null; + if(entityCustomStorage) { + entities = entityList; + } else { + entities = ((ListTag) compound.getAsListTag("Entities") + .orElse(new ListTag<>("Entities", TagType.TAG_COMPOUND, new ArrayList<>()))).getValue(); + } ListTag sectionsTag = (ListTag) compound.getAsListTag("Sections").get(); SlimeChunkSection[] sectionArray = new SlimeChunkSection[16];