created RegionChunkList

This commit is contained in:
BuildTools 2018-04-14 10:59:49 +01:00
parent d40d7a5a6f
commit 0dfa339856
4 changed files with 235 additions and 4 deletions

View file

@ -156,9 +156,6 @@ public class BackupIO
* private .mca file. It will return length 0 if there is an error
* or there is no chunk data. Otherwise, it will return the length
* value recorded in the file.
*
* below writes the backup chunk data into the target region file,
* overwriting the current chunk data in use by the game.
*/
if (length > 0)
{

View file

@ -0,0 +1,147 @@
package simpleWarBackup;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.server.v1_12_R1.RegionFile;
/**
* ---------------------------------------------------------------
* ---------------------------------------------------------------
* ---------------------------------------------------------------
* ---------------------------------------------------------------
* CURRENTLY A DUPLICATE OF THE SECONDARY CACHE IN RegionFileCache
* ---------------------------------------------------------------
* ---------------------------------------------------------------
* ---------------------------------------------------------------
* ---------------------------------------------------------------
*/
public class ChunkAccessCache
{
private static Map<RegionFile, Access> cache = new HashMap<RegionFile, Access>();
/**
* TODO
*
* @param file
* @param regionFile
*/
static void cacheChunkAccess(File file, RegionFile regionFile)
{
try
{
cache.put(regionFile, new Access(regionFile));
}
catch (FileNotFoundException |
IllegalAccessException |
IllegalArgumentException e)
{
e.printStackTrace();//TODO
}
}
/**
* TODO
*
* @param regionFile
* @param x
* @param z
* @return
*/
public static int getChunkLength(RegionFile regionFile, int x, int z)
{
Access access = cache.get(regionFile);
/* "offset" refers to the location of the chunk's bytes
* within the .mca file - or how many bytes into the file
* to seek when reading - divided by 4096.
*/
int offset;
/* The first four bytes at that location, the first four
* bytes of the chunk's data, are an int recording the
* chunk's length in bytes, not including those four.
*
* The next byte represents compression scheme. This byte,
* like the four previous bytes, is omitted when the game
* reads a chunk's data.
*
* This method returns the length of data actually read.
*/
if (access != null && (offset = access.offset[x + z * 32]) > 0)
{
try
{
access.bytes.seek(offset * 4096);
return access.bytes.readInt() - 1;
}
catch (IOException e) { e.printStackTrace(); }
}
return 0;
}
/**
* Gives access to the private fields {@code int[] d}, and {@code RandomAccessFile c},
* within a RegionFile object. The names of these fields may change in new releases of
* Spigot. TODO explain what both of those fields are
*/
private static class Access
{
static final Field offsetField;
final int[] offset;
static final Field bytesField;
final RandomAccessFile bytes;
static
{
Field tmp1 = null;
Field tmp2 = null;
try
{
tmp1 = RegionFile.class.getDeclaredField("d");
tmp1.setAccessible(true);
tmp2 = RegionFile.class.getDeclaredField("c");
tmp2.setAccessible(true);
}
catch (NoSuchFieldException | SecurityException e)
{
/* TODO take more drastic action? Either
* Field missing would mean that Minecraft
* has refactored, breaking the whole plugin
*/
e.printStackTrace();
}
offsetField = tmp1;
bytesField = tmp2;
}
/**
* Creates a new Access object to hold references to the private variables {@code int[] d}
* and {@code RandomAccessFile c} within the given RegionFile. Variables are accessed by
* reflection. TODO write more
*
* @param regionFile the RegionFile whose chunks are to be accessed
*
* @throws FileNotFoundException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
Access(RegionFile regionFile) throws FileNotFoundException,
IllegalAccessException,
IllegalArgumentException
{
offset = (int[]) offsetField.get(regionFile);
bytes = (RandomAccessFile) bytesField .get(regionFile);
}
}
}

View file

@ -1,6 +1,93 @@
package simpleWarBackup;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.BitSet;
import java.util.HashMap;
public class RegionChunkList
{
private final File file;
private final RandomAccessFile readwrite;
private final BitSet chunks = new BitSet(1024);
private final HashMap<String, HashMap
<String, HashMap
<String, RegionChunkList>>> lists =
new HashMap<String, HashMap
<String, HashMap
<String, RegionChunkList>>>();
/**
* TODO
*
* @param file
* @throws IOException
*/
RegionChunkList(File file, String backup, String town, String world) throws IOException
{
readwrite = new RandomAccessFile((this.file = file), "rw");
byte[] bytes = new byte[128];
if (readwrite.length() >= 128)
{
readwrite.readFully(bytes);
int i = 0, j, k;
for (byte b : bytes)
for (j = 0, k = 1; j < 8; i++, j++, k <<= 1)
if ((b & k) == k) chunks.set(i);
}
else readwrite.write(bytes);
lists.get(backup)
.get(town)
.put(world, this);
}
/**
* TODO
*
* @param x
* @param z
* @return
*/
boolean isChunkStored(int x, int z)
{
x &= 31;
z &= 31;
return chunks.get(x + z * 32);
}
/**
* TODO
*
* @param x
* @param z
*/
void storeChunk(int x, int z)
{
x &= 31;
z &= 31;
chunks.set(x + z * 32);
}
/**
* TODO
*
* @param x
* @param z
*/
void markChunkAsRestored(int x, int z)
{
x &= 31;
z &= 31;
chunks.clear(x + z * 32);
}
}

View file

@ -215,7 +215,7 @@ public final class RegionFileCache
}
catch (NoSuchFieldException | SecurityException e)
{
/* TODO take more drastic action. Either
/* TODO take more drastic action? Either
* Field missing would mean that Minecraft
* has refactored, breaking the whole plugin
*/