Збірка усіх плаґінів для WhoMine розроблених [MinersStudios](https://minersstudios.github.io).
package ua.com.minersstudios.whomine.util.misc;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;

/**
 * Interface to communicate with region file in one way only.
 */
final class WorldRegion extends RandomAccessFile
{
	WorldRegion(final File file, final String mode) throws FileNotFoundException
	{
		super(file, mode);
	}

	WorldRegion(final String name, final String mode) throws FileNotFoundException
	{
		super(name, mode);
	}

	private final int fourKiBSector = 4096;
	// all in bytes.
	private final int offsetSize = 3;
	private final int timestampSize = 4;
	private final int lengthSize = 4;
	private final int sectorSizeStartsAfter = 3;
	private final int compressionTypeStartsAfter = 4;
	private final int dataStartsAfter = 5;

	/// Header
	// took from Minecraft wiki.
	private int locateChunkInsideHeader(final int x, final int z) { return 4 * ((x & 31) + (z & 31) * 32); }

	/**
	 * Read given chunk's offset inside the region file from the header of the file itself.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk offset in 4 KiB sectors
	 */
	int getChunkOffset(final int x, final int z) throws IOException
	{
		byte[] rawChunkOffset = new byte[offsetSize];
		readFully(rawChunkOffset, rawChunkOffset.length, locateChunkInsideHeader(x, z));
		return ByteBuffer.allocate(rawChunkOffset.length).order(ByteOrder.BIG_ENDIAN).put(rawChunkOffset).getInt();
	}

	/**
	 * Read given chunk's disk space size from the region file.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk disk space size in 4 KiB sectors
	 */
	byte getChunkSectorCount(final int x, final int z) throws IOException
	{
		final long previousFilePointer = getFilePointer();
		seek(locateChunkInsideHeader(x, z) + sectorSizeStartsAfter);
		byte chunkSectorCount = readByte();
		seek(previousFilePointer);
		return chunkSectorCount;
	}

	/**
	 * Read given chunk's modification date from the region file.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk modification date in epoch seconds
	 */
	int getChunkModificationDate(final int x, final int z) throws IOException
	{
		byte[] rawChunkModificationDate = new byte[timestampSize];
		readFully(rawChunkModificationDate, rawChunkModificationDate.length, fourKiBSector | locateChunkInsideHeader(x, z));
		return ByteBuffer.allocate(rawChunkModificationDate.length).order(ByteOrder.BIG_ENDIAN).put(rawChunkModificationDate).getInt();
	}

	/// Data
	private int getChunkRemainingLength(final int x, final int z) throws IOException
	{
		byte[] rawChunkRemainingSize = new byte[lengthSize];
		readFully(rawChunkRemainingSize, rawChunkRemainingSize.length, getChunkOffset(x, z) * fourKiBSector);
		return ByteBuffer.allocate(rawChunkRemainingSize.length).order(ByteOrder.BIG_ENDIAN).put(rawChunkRemainingSize).getInt();
	}

	/**
	 * Read given chunk's compression type from the region file.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk compression scheme
	 */
	CompressionType getChunkCompressionType(final int x, final int z) throws IOException
	{
		final long previousFilePointer = getFilePointer();
		seek(getChunkOffset(x, z) * fourKiBSector + compressionTypeStartsAfter);
		byte rawChunkCompressionType = readByte();
		seek(previousFilePointer);
		return CompressionType.valueOf(rawChunkCompressionType);
	}

	/**
	 * Read given chunk's raw data from the region file.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk data as is
	 */
	byte[] getChunkDataPadded(final int x, final int z) throws IOException
	{
		byte[] rawChunkData = new byte[getChunkSectorCount(x, z) * fourKiBSector];
		readFully(rawChunkData, rawChunkData.length, getChunkOffset(x, z) * fourKiBSector);
		return rawChunkData;
	}

	/**
	 * Read given chunk's compressed data from the region file.
	 * @param x chunk longitude
	 * @param z chunk latitude
	 * @return chunk data in NBT data
	 */
	byte[] getChunkData(final int x, final int z) throws IOException
	{
		assert getChunkCompressionType(x, z) != CompressionType.EXTERNAL;
		byte[] rawChunkData = new byte[getChunkRemainingLength(x, z) - 1];
		readFully(rawChunkData, rawChunkData.length, getChunkOffset(x, z) * fourKiBSector + dataStartsAfter);
		return rawChunkData;
	}

	/**
	 * Characterises compression type being used in the region file.
	 * Where EXTERNAL means that chunk's data is moved into a separate file.
	 */
	@RequiredArgsConstructor
	enum CompressionType
	{
		RFC1952(1),
		RFC1950(2),
		NONE(3),
		EXTERNAL(129);

		private final int value;
		private final static List<CompressionType> values;
		static
		{
			values = new ArrayList<>();
			for (CompressionType ct : values()) values.add(ct.ordinal(), ct);
		}

		public static CompressionType valueOf(final int value)
		{
			return value < EXTERNAL.ordinal() ? values.get(value) : EXTERNAL;
		}
	}
}