created RegionChunkList
This commit is contained in:
parent
d40d7a5a6f
commit
0dfa339856
4 changed files with 235 additions and 4 deletions
|
@ -156,9 +156,6 @@ public class BackupIO
|
||||||
* private .mca file. It will return length 0 if there is an error
|
* 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
|
* or there is no chunk data. Otherwise, it will return the length
|
||||||
* value recorded in the file.
|
* 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)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
|
|
147
src/simpleWarBackup/ChunkAccessCache.java
Normal file
147
src/simpleWarBackup/ChunkAccessCache.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,93 @@
|
||||||
package simpleWarBackup;
|
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
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ public final class RegionFileCache
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException | SecurityException e)
|
catch (NoSuchFieldException | SecurityException e)
|
||||||
{
|
{
|
||||||
/* TODO take more drastic action. Either
|
/* TODO take more drastic action? Either
|
||||||
* Field missing would mean that Minecraft
|
* Field missing would mean that Minecraft
|
||||||
* has refactored, breaking the whole plugin
|
* has refactored, breaking the whole plugin
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue