RegionFileCache and BackupIO
This commit is contained in:
parent
88705dc761
commit
be8d780d5c
5 changed files with 217 additions and 61 deletions
8
plugin.yml
Normal file
8
plugin.yml
Normal 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
|
112
src/simpleWarBackup/BackupIO.java
Normal file
112
src/simpleWarBackup/BackupIO.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue