Open TealNerd opened 6 years ago
Okay you literally have a region file reading class im an idiot
Okay reopening because the SimpleRegionFileReader readFile method is returning null
The region parser doesn't work at all. I'm not really sure what format it's intended to parse. The first thing the SimpleRegionFileReader does is read an int to check the version, but the Region file format doesn't have a version field. It doesn't seem to match the old file format or the schematic file format either.
Here's the version I created, since everything else in the library works fine. I'm using this to do some offline computations on Minecraft worlds, and can verify that it works correctly.
import com.flowpowered.nbt.Tag;
import com.flowpowered.nbt.stream.NBTInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
public class RegionReader {
private static final int SECTOR_BYTES = 4096;
public static List<Tag<?>> readFile(File f) {
try (RandomAccessFile raf = new RandomAccessFile(f, "r")) {
// If there isn't a header and at least one chunk sector, the region is empty
if (raf.length() < SECTOR_BYTES * 3) {
return Collections.emptyList();
}
// Each chunk can use 1 or more sectors, and the first two sectors
// are the header, so this is the maximum number of chunks
int maxChunks = ((int) raf.length() / SECTOR_BYTES) - 2;
int[] chunkLocation = new int[maxChunks];
int entries = 0;
for (int i = 0; i < (SECTOR_BYTES / 4); i++) {
int offset = raf.readInt();
if (offset != 0) {
// The rest of the offset is the number of sectors that the chunk
// occupies. We don't care about that as each chunk stores its length
chunkLocation[entries++] = (offset >> 8) * SECTOR_BYTES;
}
}
List<Tag<?>> list = new ArrayList<>();
for (int i = 0; i < entries; i++) {
list.add(readChunk(raf, chunkLocation[i]));
}
return list;
} catch (IOException ioe) {
ioe.printStackTrace();
return null;
}
}
private static Tag<?> readChunk(RandomAccessFile raf, int location) throws IOException {
raf.seek(location);
int length = raf.readInt();
byte compressionType = raf.readByte();
byte[] data = new byte[length-1];
raf.readFully(data);
return readTag(decompress(compressionType, data));
}
private static InputStream decompress(int type, byte[] data) throws IOException {
switch (type) {
case 1: return new GZIPInputStream(new ByteArrayInputStream(data));
case 2: return new InflaterInputStream(new ByteArrayInputStream(data));
default: throw new IllegalArgumentException("Unknown type");
}
}
private static Tag<?> readTag(InputStream in) throws IOException {
return new NBTInputStream(in, false).readTag();
}
}
EDIT: I've modified the file slightly since I originally uploaded it to account for empty sectors. My revised unit tests pass.
Tried using this to parse region files and I'm getting an error right away.
new NBTInputStream(file, false).readTag()
causes an IOException with the message "TAG_End found without a TAG_Compound/TAG_List tag preceding it."
Not really sure what's happening there