RegionFileCache and BackupIO

This commit is contained in:
BuildTools 2018-01-21 16:56:04 +00:00
parent 88705dc761
commit be8d780d5c
5 changed files with 217 additions and 61 deletions

8
plugin.yml Normal file
View file

@ -0,0 +1,8 @@
main: simpleWarBackup.Main
version: 1.0.0
name: SimpleWarBackup
commands:
testBackupChun:
description: only iie gets to do this
testRestoreChunk:
description: only iie gets to do this, too

View file

@ -0,0 +1,112 @@
package simpleWarBackup;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
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.CraftWorld;
import net.minecraft.server.v1_12_R1.NBTCompressedStreamTools;
import net.minecraft.server.v1_12_R1.NBTTagCompound;
import net.minecraft.server.v1_12_R1.RegionFile;
public class BackupIO
{
private static File dataFolder, backupsFolder;
public static final HashMap<World, HashMap<String, File>> backups
= new HashMap<World, HashMap<String, File>>();
/**
* TODO
*
* @param dataFolder
* @param backupsFolder
*/
public static void initialize(File dataFolder, File backupsFolder)
{
BackupIO.dataFolder = dataFolder;
BackupIO.backupsFolder = backupsFolder;
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
*
* @param backupFolder
* @param chunkX
* @param chunkZ
* @return
*/
public static DataOutputStream chunkDataOutputStream(File backupFolder, int chunkX, int chunkZ)
{
return RegionFileCache.get(backupFolder, chunkX, chunkZ) // get(...) returns a RegionFile
.b(chunkX & 31, chunkZ & 31); // b(...) returns a DataOutputStream
}
/**
* TODO
*
* @param backup
* @param world
* @param chunks
* @throws IOException
*/
public static void backupChunks(String backup, World world, Chunk... chunks) throws IOException
{
final File folder = backups.get(world).get(backup);
final net.minecraft.server.v1_12_R1.World worldNMS
= ((CraftWorld) world).getHandle();
NBTTagCompound chunkNBT;
DataOutputStream output;
for (Chunk chunk : chunks)
{
chunkNBT = ChunkNBTWriter.write(((CraftChunk) chunk).getHandle(), worldNMS);
output = BackupIO.chunkDataOutputStream(folder, chunk.getX(), chunk.getZ());
NBTCompressedStreamTools.a(chunkNBT, (DataOutput) output);
output.close();
}
}
}

View file

@ -38,7 +38,7 @@ public final class ChunkNBTWriter
* @param DATA_VERSION
* @return
*/
public static NBTTagCompound getChunkNBT(Chunk chunk, World world)
public static NBTTagCompound write(Chunk chunk, World world)
{
NBTTagCompound chunkNBT = new NBTTagCompound();
NBTTagCompound levelNBT = new NBTTagCompound();
@ -67,7 +67,7 @@ public final class ChunkNBTWriter
* @param chunk
* @param world
*/
public static void saveEntities(NBTTagCompound levelNBT, Chunk chunk, World world)
private static void saveEntities(NBTTagCompound levelNBT, Chunk chunk, World world)
{
//the three TagLists to be written to levelNBT
NBTTagList entitiesNBT = new NBTTagList();
@ -150,7 +150,7 @@ public final class ChunkNBTWriter
* @param worldTime
* @param worldHasSkyLight
*/
public static void saveBody(NBTTagCompound levelNBT, Chunk chunk, World world)
private static void saveBody(NBTTagCompound levelNBT, Chunk chunk, World world)
{
/* passed variables worldTime and worldHasSkyLight have been
* replaced with world. The values are now obtained directly:

View file

@ -1,78 +1,57 @@
package simpleWarBackup;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_12_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import net.minecraft.server.v1_12_R1.Chunk;
import net.minecraft.server.v1_12_R1.ChunkRegionLoader;
import net.minecraft.server.v1_12_R1.DataConverterManager;
import net.minecraft.server.v1_12_R1.MinecraftServer;
import net.minecraft.server.v1_12_R1.NBTTagCompound;
import net.minecraft.server.v1_12_R1.World;
public class Main extends JavaPlugin implements Listener
{
private static File dataFolder,
backupsFolder;
public static final HashMap<org.bukkit.World, HashMap<String, File>> backups
= new HashMap<org.bukkit.World, HashMap<String, File>>();
/**
* TODO
*/
public static void mapBackupDirectoriesToWorlds()
{
/* Directories that do not exist will be made when
* the plugin attempts to save a backup for the
* given world.
*/
HashMap<String, File> map;
File worldFolder;
File backupFolder;
for (org.bukkit.World world : Bukkit.getWorlds())
{
backups.put(world, map = new HashMap<String, File>());
worldFolder = new File(backupsFolder, world.getName());
for (String backupName : worldFolder.list())
{
backupFolder = new File(worldFolder, backupName);
map.put(backupName, backupFolder);
}
}
}
public void onEnable()
{
dataFolder = this.getDataFolder();
backupsFolder = new File(dataFolder, "Backup Files");
getCommand("testBackupChunk").setExecutor(this);
getCommand("testRestoreChunk").setExecutor(this);
dataFolder.mkdir();
backupsFolder.mkdir();
mapBackupDirectoriesToWorlds();
File dataFolder = this.getDataFolder();
BackupIO.initialize(dataFolder,
new File(dataFolder,
"Backup Files"));
}
public boolean backupChunk(org.bukkit.World bukkitWorld, int chunkX, int chunkZ)
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
{
Chunk chunk = ((CraftChunk) bukkitWorld.getChunkAt(chunkX, chunkZ)).getHandle();
World world = ((CraftWorld) bukkitWorld).getHandle();
if (!(sender instanceof Player) || !sender.getName().equals("iie")) return false;
Location loc = ((Player) sender).getLocation();
World world = loc.getWorld();
Chunk chunk = loc.getChunk();
if (label.equals("testBackupChunk"))
{
try {
BackupIO.backupChunks("test", world, chunk);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if (label.equals("testRestoreChunk"))
{
}
return true;
}
}

View file

@ -1,13 +1,70 @@
package simpleWarBackup;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.google.common.collect.Maps;
import net.minecraft.server.v1_12_R1.RegionFile;
/**
* TODO write this
*/
public class RegionFileCache
{
public static final Map<File, RegionFile> files = Maps.newHashMap();
private static final Map<File, RegionFile> regionFiles = new HashMap<File, RegionFile>();
/**
* Copied from net.minecraft.server.RefionFileCache.a(File, int, int). 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.clearCace()}.
*
* @param backupFolder folder containing "region" folder
* @param x chunk X
* @param z chunk Z
* @return
*/
public static synchronized RegionFile get(File backupFolder, int x, int z)
{
x >>= 5; z >>= 5;
File regionFolder = new File(backupFolder, "region");
File regionFileFile = new File(regionFolder, "r." + x + "." + z + ".mca");
RegionFile regionFile = regionFiles.get(regionFileFile);
if (regionFile != null)
return regionFile;
if (!regionFolder.exists())
regionFolder.mkdirs();
if (regionFiles.size() >= 16)
clearCache();
regionFile = new RegionFile(regionFileFile);
RegionFileCache.regionFiles.put(regionFileFile, regionFile);
return regionFile;
}
/**
* Copied from net.minecraft.server.RegionFileCache.a(). Iterates through all cached
* RegionFiles, closing each one's private RandomAccessFile, then clears the cache.
*/
public static synchronized void clearCache()
{
Iterator<RegionFile> iterator = RegionFileCache.regionFiles.values().iterator();
/* regionFile.c() closes the private RandomAccessFile
* inside the regionFile object, and that's all it does.
* The entire method: if (file != null) file.close().
*/
while (iterator.hasNext())
{
RegionFile regionFile = iterator.next();
try { if (regionFile != null) regionFile.c(); }
catch (IOException e) { e.printStackTrace(); }
}
RegionFileCache.regionFiles.clear();
}
}