@@ -42,6 +42,7 @@ public class SWMImporter {
4242
4343 private static final Pattern MAP_FILE_PATTERN = Pattern .compile ("^(?:map_([0-9]*).dat)$" );
4444 private static final int SECTOR_SIZE = 4096 ;
45+ private static boolean entityCustomStorage ;
4546
4647 public static void main (String [] args ) {
4748 if (args .length == 0 ) {
@@ -132,6 +133,14 @@ public static void importWorld(File worldFolder, File outputFile, boolean debug)
132133 throw new InvalidWorldException (worldFolder , "The world appears to be corrupted" );
133134 }
134135
136+ File entitiesDir = new File (worldFolder , "entities" );
137+
138+ if (entitiesDir .exists ()) {
139+ entityCustomStorage = true ;
140+
141+ if (debug ) System .out .println ("Entities will be imported from custom storage (1.17 world or above)" );
142+ }
143+
135144 if (debug ) System .out .println ("Loading world..." );
136145
137146 File levelFile = new File (worldFolder , "level.dat" );
@@ -171,7 +180,7 @@ public static void importWorld(File worldFolder, File outputFile, boolean debug)
171180
172181 for (File file : regionDir .listFiles ((dir , name ) -> name .endsWith (".mca" ))) {
173182 try {
174- chunks .addAll (loadChunks (file , worldVersion , debug ));
183+ chunks .addAll (loadChunks (file , entitiesDir , worldVersion , debug ));
175184 } catch (IOException ex ) {
176185 throw new IOException ("Failed to read region file" , ex );
177186 }
@@ -248,7 +257,7 @@ private static CompoundTag loadMap(File mapFile) throws IOException {
248257 return tag ;
249258 }
250259
251- private static List <SlimeChunk > loadChunks (File file , byte worldVersion , boolean debug ) throws IOException {
260+ private static List <SlimeChunk > loadChunks (File file , File entitiesDir , byte worldVersion , boolean debug ) throws IOException {
252261 if (debug ) System .out .println ("Loading chunks from region file '" + file .getName () + "':" );
253262
254263 byte [] regionByteArray = Files .readAllBytes (file .toPath ());
@@ -287,7 +296,12 @@ private static List<SlimeChunk> loadChunks(File file, byte worldVersion, boolean
287296
288297 CompoundTag levelCompound = (CompoundTag ) globalMap .get ("Level" );
289298
290- return readChunk (levelCompound , worldVersion );
299+ List <CompoundTag > entityList = null ;
300+
301+ if (entityCustomStorage )
302+ entityList = readEntities (file , entitiesDir , entry .getOffset (), entry .getPaddedSize (), worldVersion , debug );
303+
304+ return readChunk (levelCompound , entityList , worldVersion );
291305 } catch (IOException ex ) {
292306 throw new RuntimeException (ex );
293307 }
@@ -299,7 +313,46 @@ private static List<SlimeChunk> loadChunks(File file, byte worldVersion, boolean
299313 return loadedChunks ;
300314 }
301315
302- private static SlimeChunk readChunk (CompoundTag compound , byte worldVersion ) {
316+ private static List <CompoundTag > readEntities (File regionFile , File entityDir , int offset , int paddedSize , byte worldVersion , boolean debug ) throws IOException {
317+ File file = new File (entityDir .getPath (), regionFile .getName ());
318+ List <CompoundTag > entities = new ListTag <CompoundTag >("Entities" , TagType .TAG_COMPOUND , new ArrayList <>()).getValue ();
319+
320+ if (!file .exists ()) {
321+ return entities ;
322+ }
323+
324+ if (debug ) System .out .println ("Loading chunk entities from region file '" + file .getName () + "':" );
325+
326+ byte [] regionByteArray = Files .readAllBytes (file .toPath ());
327+
328+ try {
329+ DataInputStream headerStream = new DataInputStream (new ByteArrayInputStream (regionByteArray , offset , paddedSize ));
330+
331+ if (headerStream .available () <= 0 ) {
332+ return entities ;
333+ }
334+
335+ int chunkSize = headerStream .readInt () - 1 ;
336+
337+ int compressionScheme = headerStream .readByte ();
338+
339+ DataInputStream chunkStream = new DataInputStream (new ByteArrayInputStream (regionByteArray , offset + 5 , chunkSize ));
340+ InputStream decompressorStream = compressionScheme == 1 ? new GZIPInputStream (chunkStream ) : new InflaterInputStream (chunkStream );
341+ NBTInputStream nbtStream = new NBTInputStream (decompressorStream , NBTInputStream .NO_COMPRESSION , ByteOrder .BIG_ENDIAN );
342+ CompoundTag globalCompound = (CompoundTag ) nbtStream .readTag ();
343+
344+ entities = ((ListTag <CompoundTag >) globalCompound .getAsListTag ("Entities" )
345+ .orElse (new ListTag <>("Entities" , TagType .TAG_COMPOUND , new ArrayList <>()))).getValue ();
346+ } catch (IOException ex ) {
347+ throw new RuntimeException (ex );
348+ }
349+
350+ if (debug ) System .out .println ( entities .size () + " entities loaded at " + regionFile .getName ());
351+
352+ return entities ;
353+ }
354+
355+ private static SlimeChunk readChunk (CompoundTag compound , List <CompoundTag > entityList , byte worldVersion ) {
303356 int chunkX = compound .getAsIntTag ("xPos" ).get ().getValue ();
304357 int chunkZ = compound .getAsIntTag ("zPos" ).get ().getValue ();
305358 Optional <String > status = compound .getStringValue ("Status" );
@@ -336,8 +389,13 @@ private static SlimeChunk readChunk(CompoundTag compound, byte worldVersion) {
336389
337390 List <CompoundTag > tileEntities = ((ListTag <CompoundTag >) compound .getAsListTag ("TileEntities" )
338391 .orElse (new ListTag <>("TileEntities" , TagType .TAG_COMPOUND , new ArrayList <>()))).getValue ();
339- List <CompoundTag > entities = ((ListTag <CompoundTag >) compound .getAsListTag ("Entities" )
340- .orElse (new ListTag <>("Entities" , TagType .TAG_COMPOUND , new ArrayList <>()))).getValue ();
392+ List <CompoundTag > entities = null ;
393+ if (entityCustomStorage ) {
394+ entities = entityList ;
395+ } else {
396+ entities = ((ListTag <CompoundTag >) compound .getAsListTag ("Entities" )
397+ .orElse (new ListTag <>("Entities" , TagType .TAG_COMPOUND , new ArrayList <>()))).getValue ();
398+ }
341399 ListTag <CompoundTag > sectionsTag = (ListTag <CompoundTag >) compound .getAsListTag ("Sections" ).get ();
342400 SlimeChunkSection [] sectionArray = new SlimeChunkSection [16 ];
343401
0 commit comments