package org.pepsoft.minecraft;
/*
** 2011 January 5
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
*/
/*
* 2011 February 16
*
* This source code is based on the work of Scaevolus (see notice above).
* It has been slightly modified by Mojang AB to limit the maximum cache
* size (relevant to extremely big worlds on Linux systems with limited
* number of file handles). The region files are postfixed with ".mcr"
* (Minecraft region file) instead of ".data" to differentiate from the
* original McRegion files.
*
*/
// A simple cache and wrapper for efficiently multiple RegionFiles simultaneously.
import java.io.*;
import java.lang.ref.*;
import java.util.*;
import static org.pepsoft.minecraft.Constants.*;
public final class RegionFileCache {
private static final int MAX_CACHE_SIZE = 256;
private static final Map<File, Reference<RegionFile>> cache = new HashMap<>(), readOnlyCache = new HashMap<>();
private RegionFileCache() {
}
public static synchronized RegionFile getRegionFileIfExists(File basePath, int chunkX, int chunkZ, int version) throws IOException {
return getRegionFileIfExists(basePath, chunkX, chunkZ, version, false);
}
public static synchronized RegionFile getRegionFileIfExists(File basePath, int chunkX, int chunkZ, int version, boolean readOnly) throws IOException {
if ((version != SUPPORTED_VERSION_1) && (version != SUPPORTED_VERSION_2)) {
throw new IllegalArgumentException("Not a supported version: 0x" + Integer.toHexString(version));
}
File regionDir = new File(basePath, "region");
if (!regionDir.exists()) {
return null;
}
File file = new File(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + ((version == SUPPORTED_VERSION_1) ? ".mcr" : ".mca"));
Reference<RegionFile> ref = readOnly ? readOnlyCache.get(file) : cache.get(file);
RegionFile regionFile = (ref != null) ? ref.get() : null;
if (regionFile != null) {
return regionFile;
}
if (! file.isFile()) {
return null;
}
if ((readOnly ? readOnlyCache.size() : cache.size()) >= MAX_CACHE_SIZE) {
RegionFileCache.clear();
}
regionFile = new RegionFile(file, readOnly);
(readOnly ? readOnlyCache : cache).put(file, new SoftReference<>(regionFile));
return regionFile;
}
public static synchronized RegionFile getRegionFile(File basePath, int chunkX, int chunkZ, int version) throws IOException {
if ((version != SUPPORTED_VERSION_1) && (version != SUPPORTED_VERSION_2)) {
throw new IllegalArgumentException("Not a supported version: 0x" + Integer.toHexString(version));
}
File regionDir = new File(basePath, "region");
File file = new File(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + ((version == SUPPORTED_VERSION_1) ? ".mcr" : ".mca"));
Reference<RegionFile> ref = cache.get(file);
RegionFile regionFile = (ref != null) ? ref.get() : null;
if (regionFile != null) {
return regionFile;
}
if (!regionDir.exists()) {
regionDir.mkdirs();
}
if (cache.size() >= MAX_CACHE_SIZE) {
RegionFileCache.clear();
}
regionFile = new RegionFile(file);
cache.put(file, new SoftReference<>(regionFile));
return regionFile;
}
public static synchronized void clear() throws IOException {
for (Reference<RegionFile> ref : cache.values()) {
if (ref.get() != null) {
ref.get().close();
}
}
cache.clear();
}
public static int getSizeDelta(File basePath, int chunkX, int chunkZ, int version) throws IOException {
RegionFile r = getRegionFile(basePath, chunkX, chunkZ, version);
return r.getSizeDelta();
}
public static DataInputStream getChunkDataInputStream(File basePath, int chunkX, int chunkZ, int version) throws IOException {
RegionFile r = getRegionFile(basePath, chunkX, chunkZ, version);
return r.getChunkDataInputStream(chunkX & 31, chunkZ & 31);
}
public static DataOutputStream getChunkDataOutputStream(File basePath, int chunkX, int chunkZ, int version) throws IOException {
RegionFile r = getRegionFile(basePath, chunkX, chunkZ, version);
return r.getChunkDataOutputStream(chunkX & 31, chunkZ & 31);
}
}