"Restore" test, fails currently
added a restore chunks command for two test chunks. Currently does not manage to write to the main world file.
This commit is contained in:
parent
ffed682beb
commit
fda2afbd49
4 changed files with 312 additions and 113 deletions
|
@ -1,113 +1,180 @@
|
||||||
package simpleWarBackup;
|
package simpleWarBackup;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.CraftChunk;
|
import org.bukkit.craftbukkit.v1_12_R1.CraftChunk;
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_12_R1.Chunk;
|
||||||
import net.minecraft.server.v1_12_R1.NBTCompressedStreamTools;
|
import net.minecraft.server.v1_12_R1.NBTCompressedStreamTools;
|
||||||
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
||||||
import net.minecraft.server.v1_12_R1.RegionFile;
|
import net.minecraft.server.v1_12_R1.RegionFile;
|
||||||
|
import net.minecraft.server.v1_12_R1.World;
|
||||||
|
|
||||||
public class BackupIO
|
public class BackupIO
|
||||||
{
|
{
|
||||||
private static File dataFolder, backupsFolder;
|
private static File pluginDir, backupsDir;
|
||||||
|
|
||||||
public static final HashMap<World, HashMap<String, File>> backups
|
protected static void initialize(JavaPlugin plugin)
|
||||||
= new HashMap<World, HashMap<String, File>>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @param dataFolder
|
|
||||||
* @param backupsFolder
|
|
||||||
*/
|
|
||||||
public static void initialize(File dataFolder, File backupsFolder)
|
|
||||||
{
|
{
|
||||||
BackupIO.dataFolder = dataFolder;
|
pluginDir = plugin.getDataFolder();
|
||||||
BackupIO.backupsFolder = backupsFolder;
|
backupsDir = new File(pluginDir, "Backup Files");
|
||||||
BackupIO.dataFolder.mkdir();
|
|
||||||
BackupIO.backupsFolder.mkdir();
|
|
||||||
|
|
||||||
initializeBackupsMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
public static void initializeBackupsMap()
|
|
||||||
{
|
|
||||||
HashMap<String, File> map;
|
|
||||||
File worldFolder;
|
|
||||||
File backupFolder;
|
|
||||||
|
|
||||||
/* Directories that do not exist will be made when
|
|
||||||
* the plugin attempts to save a backup for the
|
|
||||||
* given world.
|
|
||||||
*/
|
|
||||||
for (World world : Bukkit.getWorlds())
|
|
||||||
{
|
|
||||||
backups.put(world, map = new HashMap<String, File>());
|
|
||||||
worldFolder = new File(backupsFolder, world.getName());
|
|
||||||
if (worldFolder.exists() && worldFolder.list() != null)
|
|
||||||
{
|
|
||||||
for (String backupName : worldFolder.list())
|
|
||||||
{
|
|
||||||
backupFolder = new File(worldFolder, backupName);
|
|
||||||
map.put(backupName, backupFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @param backupFolder
|
* @param world
|
||||||
* @param chunkX
|
* @param backup
|
||||||
* @param chunkZ
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static DataOutputStream chunkDataOutputStream(File backupFolder, int chunkX, int chunkZ)
|
private static File getBackupDir(CraftWorld world, String backup)
|
||||||
{
|
{
|
||||||
return RegionFileCache.get(backupFolder, chunkX, chunkZ) // get(...) returns a RegionFile
|
return new File(new File(backupsDir, world.getName()), backup);
|
||||||
.b(chunkX & 31, chunkZ & 31); // b(...) returns a DataOutputStream
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
* @param backup
|
|
||||||
* @param world
|
* @param world
|
||||||
|
* @param backup
|
||||||
* @param chunks
|
* @param chunks
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static void backupChunks(String backup, World world, Chunk... chunks) throws IOException
|
public static void backup(
|
||||||
|
CraftWorld world, String backup, CraftChunk... chunks)
|
||||||
|
throws IOException
|
||||||
{
|
{
|
||||||
System.out.println("backupChunks has been called");//TODO
|
final World worldNMS = world.getHandle();
|
||||||
final File folder = backups.get(world).get(backup);
|
Chunk chunkNMS;
|
||||||
final net.minecraft.server.v1_12_R1.World worldNMS
|
NBTTagCompound chunkNBT; // to be serialized
|
||||||
= ((CraftWorld) world).getHandle();
|
|
||||||
|
|
||||||
NBTTagCompound chunkNBT;
|
final File backupDir = getBackupDir(world, backup);
|
||||||
DataOutputStream output;
|
int x, z;
|
||||||
|
RegionFile regionFile;
|
||||||
|
DataOutputStream chunkPipe; // serialized to this
|
||||||
|
|
||||||
for (Chunk chunk : chunks)
|
/* chunkPipe is a series of data outputs pointing to a ChunkBuffer.
|
||||||
|
* The internal class ChunkBuffer is defined within RegionFile, and
|
||||||
|
* extends ByteArrayOutputStream. It holds a byte[] buffer and two
|
||||||
|
* int values representing the chunk's coordinates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (CraftChunk chunk : chunks)
|
||||||
{
|
{
|
||||||
chunkNBT = ChunkNBTWriter.write(((CraftChunk) chunk).getHandle(), worldNMS);
|
chunkNMS = chunk.getHandle();
|
||||||
output = BackupIO.chunkDataOutputStream(folder, chunk.getX(), chunk.getZ());
|
chunkNBT = ChunkNBTTools.save(chunkNMS, worldNMS);
|
||||||
|
|
||||||
NBTCompressedStreamTools.a(chunkNBT, (DataOutput) output);
|
x = chunk.getX();
|
||||||
output.close();
|
z = chunk.getZ();
|
||||||
|
regionFile = RegionFileCache.get(backupDir, x, z);
|
||||||
|
chunkPipe = regionFile.b(x & 31, z & 31);
|
||||||
|
|
||||||
|
/* below serializes chunkNBT and writes the bytes to chunkPipe,
|
||||||
|
* which then, on close(), writes those bytes into the RegionFile's
|
||||||
|
* internal RandomAccessFile, which points to the actual .mca file.
|
||||||
|
*/
|
||||||
|
NBTCompressedStreamTools.a(chunkNBT, (DataOutput) chunkPipe);
|
||||||
|
chunkPipe.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param world
|
||||||
|
* @param backup
|
||||||
|
* @param chunks
|
||||||
|
*/
|
||||||
|
private static void restoreWhenSafe(CraftWorld world, String backup, long[] chunks)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param world
|
||||||
|
* @param backup
|
||||||
|
*/
|
||||||
|
private static void restoreWhenSafe(CraftWorld world, String backup)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
File worldDir = new File(backupsDir, world.getName());
|
||||||
|
File backupDir = new File(worldDir, backup);
|
||||||
|
File regionDir = new File(backupDir, "region");
|
||||||
|
|
||||||
|
if (!regionDir.exists() ||
|
||||||
|
!regionDir.isDirectory())
|
||||||
|
return;
|
||||||
|
|
||||||
|
String[] regionFileNames = regionDir.list();
|
||||||
|
if (regionFileNames == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (String regionFileName : regionFileNames)
|
||||||
|
{
|
||||||
|
//TODO BLAHAHAHABLHABLHBALJHBFLJDHBFKWYBFKUHEBF
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean restoreTest(int x, int z) throws IOException
|
||||||
|
{
|
||||||
|
CraftWorld world = (CraftWorld) Bukkit.getWorld("world");
|
||||||
|
|
||||||
|
File worldDir = new File(backupsDir, "world");
|
||||||
|
File backupDir = new File(worldDir, "test");
|
||||||
|
File regionDir = new File(backupDir, "region");
|
||||||
|
File mcaFile = new File(regionDir, "r.1.1.mca");
|
||||||
|
|
||||||
|
RegionFile regionFileSource = RegionFileCache.get(backupDir, x, z);
|
||||||
|
RegionFile regionFileTarget = RegionFileCache.getFromMinecraft(world, x, z);
|
||||||
|
|
||||||
|
DataInputStream dataInput = regionFileSource.a(x & 31, z & 31);
|
||||||
|
DataOutputStream dataOutput = regionFileTarget.b(x & 31, z & 31);
|
||||||
|
|
||||||
|
/* Look in RegionFile to find how to get length.
|
||||||
|
* Length is recorded in the first 4 bytes of each
|
||||||
|
* chunk's data, in the body of the region file.
|
||||||
|
*
|
||||||
|
* Read header for chunk data location, seek to
|
||||||
|
* that location and read first 4 bytes. This is
|
||||||
|
* the length for byte[] buf below.
|
||||||
|
*/
|
||||||
|
/*int length;
|
||||||
|
{
|
||||||
|
RandomAccessFile raf = RegionFileCache.getRAF(regionFileSource);
|
||||||
|
if (raf == null) return false;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buf = new byte[length];
|
||||||
|
|
||||||
|
dataInput.readFully(buf);
|
||||||
|
dataOutput.write(buf);
|
||||||
|
dataOutput.close();*/
|
||||||
|
|
||||||
|
if (dataInput == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NBTCompressedStreamTools.a(
|
||||||
|
NBTCompressedStreamTools.a(dataInput),
|
||||||
|
(java.io.DataOutput) dataOutput);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import net.minecraft.server.v1_12_R1.World;
|
||||||
* methods in ChunkRegionLoader, an NMS class. Changes have been commented, so that these
|
* methods in ChunkRegionLoader, an NMS class. Changes have been commented, so that these
|
||||||
* methods may be more easily updated as Spigot releases newer versions.
|
* methods may be more easily updated as Spigot releases newer versions.
|
||||||
*/
|
*/
|
||||||
public final class ChunkNBTWriter
|
public final class ChunkNBTTools
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* To find the new data version after an update,
|
* To find the new data version after an update,
|
||||||
|
@ -38,7 +38,7 @@ public final class ChunkNBTWriter
|
||||||
* @param DATA_VERSION
|
* @param DATA_VERSION
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static NBTTagCompound write(Chunk chunk, World world)
|
public static NBTTagCompound save(Chunk chunk, World world)
|
||||||
{
|
{
|
||||||
System.out.println("ChunkNBTWriter.write has been called");//TODO
|
System.out.println("ChunkNBTWriter.write has been called");//TODO
|
||||||
NBTTagCompound chunkNBT = new NBTTagCompound();
|
NBTTagCompound chunkNBT = new NBTTagCompound();
|
||||||
|
@ -47,8 +47,8 @@ public final class ChunkNBTWriter
|
||||||
chunkNBT.set("Level", levelNBT);
|
chunkNBT.set("Level", levelNBT);
|
||||||
chunkNBT.setInt("DataVersion", DATA_VERSION);
|
chunkNBT.setInt("DataVersion", DATA_VERSION);
|
||||||
|
|
||||||
ChunkNBTWriter.saveEntities(levelNBT, chunk, world);
|
ChunkNBTTools.saveEntities(levelNBT, chunk, world);
|
||||||
ChunkNBTWriter.saveBody(levelNBT, chunk, world);
|
ChunkNBTTools.saveBody(levelNBT, chunk, world);
|
||||||
|
|
||||||
return chunkNBT;
|
return chunkNBT;
|
||||||
}
|
}
|
|
@ -23,37 +23,56 @@ public class Main extends JavaPlugin implements Listener
|
||||||
getCommand("testBackupChunk").setExecutor(this);
|
getCommand("testBackupChunk").setExecutor(this);
|
||||||
getCommand("testRestoreChunk").setExecutor(this);
|
getCommand("testRestoreChunk").setExecutor(this);
|
||||||
|
|
||||||
File dataFolder = this.getDataFolder();
|
BackupIO.initialize(this);
|
||||||
BackupIO.initialize(dataFolder,
|
|
||||||
new File(dataFolder,
|
|
||||||
"Backup Files"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||||
{
|
{
|
||||||
if (!(sender instanceof Player) || !sender.getName().equals("iie")) return false;
|
if (!(sender instanceof Player)) return false;
|
||||||
System.out.println("player is iie");//TODO
|
if (!sender.getName().equals("iie")) return false;
|
||||||
|
|
||||||
|
sender.sendMessage("some command received");
|
||||||
Location loc = ((Player) sender).getLocation();
|
Location loc = ((Player) sender).getLocation();
|
||||||
|
World world = loc.getWorld();
|
||||||
|
Chunk chunk = loc.getChunk();
|
||||||
|
|
||||||
World world = loc.getWorld();
|
//test-chunks to be test-restored
|
||||||
Chunk chunk = loc.getChunk();
|
int[][] xz = {{187, 187},
|
||||||
|
{40 , 40 }};
|
||||||
|
|
||||||
if (command.getName().equals("testBackupChunk"))
|
if (command.getName().equals("testBackupChunk"))
|
||||||
{
|
{
|
||||||
System.out.println("command label = testBackupChunk");//TODO
|
try { BackupIO.backup((CraftWorld) world, "test", (CraftChunk) chunk); }
|
||||||
try {
|
catch (IOException e) { e.printStackTrace(); }
|
||||||
BackupIO.backupChunks("test", world, chunk);
|
|
||||||
System.out.println("tried BackupIO.backupChunks");//TODO
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (command.getName().equals("testRestoreChunk"))
|
||||||
else if (label.equals("testRestoreChunk"))
|
|
||||||
{
|
{
|
||||||
|
sender.sendMessage("testRestoreChunk command received");
|
||||||
|
for (int[] coords : xz)
|
||||||
|
{
|
||||||
|
if (world.isChunkLoaded(coords[0], coords[1]))
|
||||||
|
{
|
||||||
|
sender.sendMessage("chunk " + coords[0] + ", " + coords[1] + " is still loaded");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
sender.sendMessage("chunk is not loaded");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int[] coords : xz)
|
||||||
|
{
|
||||||
|
sender.sendMessage(
|
||||||
|
BackupIO.restoreTest(coords[0], coords[1]) ? "restore worked" :
|
||||||
|
"restore failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
sender.sendMessage("IOException, restore failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,71 @@
|
||||||
package simpleWarBackup;
|
package simpleWarBackup;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
||||||
|
|
||||||
import net.minecraft.server.v1_12_R1.RegionFile;
|
import net.minecraft.server.v1_12_R1.RegionFile;
|
||||||
|
import net.minecraft.server.v1_12_R1.World;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO write this
|
* TODO write this
|
||||||
*/
|
*/
|
||||||
public class RegionFileCache
|
public final class RegionFileCache
|
||||||
{
|
{
|
||||||
private static final Map<File, RegionFile> regionFiles = new HashMap<File, RegionFile>();
|
private static final int cap = 16; //capacity - how many regionFiles to keep cached
|
||||||
|
private static final Map<File, RegionFile> cache = new HashMap<File, RegionFile>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copied from net.minecraft.server.RefionFileCache.a(File, int, int). Returns any
|
* Returns name of the region file that would contain the given chunk coordinates.
|
||||||
* cached RegionFile mapped to the given File. Not finding one, creates and caches,
|
* Name follows the standard minecraft format: "r.[region x].[region z].mca".
|
||||||
* then returns, a new RegionFile. Before caching a new RegionFile, checks that the
|
* Region coordinate = chunk coordinate >> 5.
|
||||||
* cache contains fewer than 16 RegionFiles, and, finding 16 or more, calls
|
|
||||||
* {@link #clearCache() RegionFileCache.clearCace()}.
|
|
||||||
*
|
*
|
||||||
* @param backupFolder folder containing "region" folder
|
* @param x global chunk coordinate x
|
||||||
* @param x chunk X
|
* @param z global chunk coordinate z
|
||||||
* @param z chunk Z
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static synchronized RegionFile get(File backupFolder, int x, int z)
|
public static String path(int x, int z)
|
||||||
{
|
{
|
||||||
System.out.println("RegionFileCache.get has been called");//TODO
|
return "r." + (x >> 5) + "." + (z >> 5) + ".mca";
|
||||||
x >>= 5; z >>= 5;
|
}
|
||||||
File regionFolder = new File(backupFolder, "region");
|
|
||||||
File regionFileFile = new File(regionFolder, "r." + x + "." + z + ".mca");
|
/**
|
||||||
RegionFile regionFile = regionFiles.get(regionFileFile);
|
* Copied from net.minecraft.server.RefionFileCache.a(File, int, int).<p>
|
||||||
|
*
|
||||||
|
* Returns any cached RegionFile mapped to the given File. Not finding one, creates
|
||||||
|
* and caches, then returns, a new RegionFile. Before caching a new RegionFile, checks
|
||||||
|
* that the cache contains fewer than 16 RegionFiles, and, finding 16 or more, calls
|
||||||
|
* {@link #clearCache() RegionFileCache.clearCache()}.
|
||||||
|
*
|
||||||
|
* @param backupDir where to look for a "region" folder
|
||||||
|
* @param x global chunk coordinate x
|
||||||
|
* @param z global chunk coordinate z
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static synchronized RegionFile get(File backupDir, int x, int z)
|
||||||
|
{
|
||||||
|
File regionDir = new File(backupDir, "region");
|
||||||
|
File mcaFile = new File(regionDir, path(x,z));
|
||||||
|
|
||||||
|
RegionFile regionFile = cache.get(mcaFile);
|
||||||
|
|
||||||
if (regionFile != null)
|
if (regionFile != null)
|
||||||
return regionFile;
|
return regionFile;
|
||||||
if (!regionFolder.exists())
|
if (!regionDir.exists())
|
||||||
regionFolder.mkdirs();
|
regionDir.mkdirs();
|
||||||
if (regionFiles.size() >= 16)
|
if (cache.size() >= cap)
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
||||||
regionFile = new RegionFile(regionFileFile);
|
regionFile = new RegionFile(mcaFile);
|
||||||
RegionFileCache.regionFiles.put(regionFileFile, regionFile);
|
RegionFileCache.cache.put(mcaFile, regionFile);
|
||||||
|
RegionFileCache.cacheRAF(mcaFile, regionFile);
|
||||||
return regionFile;
|
return regionFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +76,7 @@ public class RegionFileCache
|
||||||
*/
|
*/
|
||||||
public static synchronized void clearCache()
|
public static synchronized void clearCache()
|
||||||
{
|
{
|
||||||
Iterator<RegionFile> iterator = RegionFileCache.regionFiles.values().iterator();
|
Iterator<RegionFile> iterator = RegionFileCache.cache.values().iterator();
|
||||||
|
|
||||||
/* regionFile.c() closes the private RandomAccessFile
|
/* regionFile.c() closes the private RandomAccessFile
|
||||||
* inside the regionFile object, and that's all it does.
|
* inside the regionFile object, and that's all it does.
|
||||||
|
@ -66,6 +88,97 @@ public class RegionFileCache
|
||||||
try { if (regionFile != null) regionFile.c(); }
|
try { if (regionFile != null) regionFile.c(); }
|
||||||
catch (IOException e) { e.printStackTrace(); }
|
catch (IOException e) { e.printStackTrace(); }
|
||||||
}
|
}
|
||||||
RegionFileCache.regionFiles.clear();
|
RegionFileCache.cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param world
|
||||||
|
* @param x
|
||||||
|
* @param z
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static RegionFile getFromMinecraft(CraftWorld world, int x, int z)
|
||||||
|
{
|
||||||
|
/* root directory of the world, the directory
|
||||||
|
* sharing the world's name and holding its
|
||||||
|
* data. 'region' folder is found in here.
|
||||||
|
*/
|
||||||
|
File dir = world.getHandle().getDataManager().getDirectory();
|
||||||
|
|
||||||
|
return net.minecraft.server.v1_12_R1.RegionFileCache.a(dir, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param world
|
||||||
|
* @param x
|
||||||
|
* @param z
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static RegionFile getFromMinecraft(World world, int x, int z)
|
||||||
|
{
|
||||||
|
/* root directory of the world, the directory
|
||||||
|
* sharing the world's name and holding its
|
||||||
|
* data. 'region' folder is found in here.
|
||||||
|
*/
|
||||||
|
File dir = world.getDataManager().getDirectory();
|
||||||
|
|
||||||
|
return net.minecraft.server.v1_12_R1.RegionFileCache.a(dir, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------RandomAccessFiles-------------------------------*/
|
||||||
|
|
||||||
|
/* RegionFiles keep their actual .mca files private, but those bytes can be useful
|
||||||
|
* to read. The auxiliary cache below stores, for each cached RegionFile, a read-only
|
||||||
|
* RandomAccessFile pointing to the .mca file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static Map<RegionFile,
|
||||||
|
RandomAccessFile> cacheRAF = new HashMap<RegionFile,
|
||||||
|
RandomAccessFile>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* @param regionFile
|
||||||
|
*/
|
||||||
|
private static void cacheRAF(File file, RegionFile regionFile)
|
||||||
|
{
|
||||||
|
try { cacheRAF.put(regionFile, new RandomAccessFile(file, "r")); }
|
||||||
|
catch (FileNotFoundException e) { e.printStackTrace(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param regionFile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static RandomAccessFile getRAF(RegionFile regionFile)
|
||||||
|
{
|
||||||
|
return cacheRAF.get(regionFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param regionFile
|
||||||
|
* @param x
|
||||||
|
* @param z
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int getChunkByteLength(RegionFile regionFile, int x, int z)
|
||||||
|
{
|
||||||
|
return 0;//TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue