package net.minecraft.world.storage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Logger;
import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.chunk.storage.IChunkLoader;
public class SaveHandler implements ISaveHandler, IPlayerFileData
{
/** Reference to the logger. */
private static final Logger logger = Logger.getLogger("Minecraft");
/** The directory in which to save world data. */
private final File worldDirectory;
/** The directory in which to save player data. */
private final File playersDirectory;
private final File mapDataDir;
/**
* The time in milliseconds when this field was initialized. Stored in the session lock file.
*/
private final long initializationTime = System.currentTimeMillis();
/** The directory name of the world */
private final String saveDirectoryName;
public SaveHandler(File par1File, String par2Str, boolean par3)
{
this.worldDirectory = new File(par1File, par2Str);
this.worldDirectory.mkdirs();
this.playersDirectory = new File(this.worldDirectory, "players");
this.mapDataDir = new File(this.worldDirectory, "data");
this.mapDataDir.mkdirs();
this.saveDirectoryName = par2Str;
if (par3)
{
this.playersDirectory.mkdirs();
}
this.setSessionLock();
}
/**
* Creates a session lock file for this process
*/
private void setSessionLock()
{
try
{
File var1 = new File(this.worldDirectory, "session.lock");
DataOutputStream var2 = new DataOutputStream(new FileOutputStream(var1));
try
{
var2.writeLong(this.initializationTime);
}
finally
{
var2.close();
}
}
catch (IOException var7)
{
var7.printStackTrace();
throw new RuntimeException("Failed to check session lock, aborting");
}
}
/**
* gets the File object corresponding to the base directory of this save (saves/404 for a save called 404 etc)
*/
public File getSaveDirectory()
{
return this.worldDirectory;
}
/**
* Checks the session lock to prevent save collisions
*/
public void checkSessionLock() throws MinecraftException
{
try
{
File var1 = new File(this.worldDirectory, "session.lock");
DataInputStream var2 = new DataInputStream(new FileInputStream(var1));
try
{
if (var2.readLong() != this.initializationTime)
{
throw new MinecraftException("The save is being accessed from another location, aborting");
}
}
finally
{
var2.close();
}
}
catch (IOException var7)
{
throw new MinecraftException("Failed to check session lock, aborting");
}
}
/**
* Returns the chunk loader with the provided world provider
*/
public IChunkLoader getChunkLoader(WorldProvider par1WorldProvider)
{
throw new RuntimeException("Old Chunk Storage is no longer supported.");
}
/**
* Loads and returns the world info
*/
public WorldInfo loadWorldInfo()
{
File var1 = new File(this.worldDirectory, "level.dat");
NBTTagCompound var2;
NBTTagCompound var3;
WorldInfo worldInfo = null;
if (var1.exists())
{
try
{
var2 = CompressedStreamTools.readCompressed(new FileInputStream(var1));
var3 = var2.getCompoundTag("Data");
worldInfo = new WorldInfo(var3);
FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, var2);
return worldInfo;
}
catch (Exception var5)
{
if (FMLCommonHandler.instance().shouldServerBeKilledQuietly())
{
throw (RuntimeException)var5;
}
var5.printStackTrace();
}
}
var1 = new File(this.worldDirectory, "level.dat_old");
if (var1.exists())
{
try
{
var2 = CompressedStreamTools.readCompressed(new FileInputStream(var1));
var3 = var2.getCompoundTag("Data");
worldInfo = new WorldInfo(var3);
FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, var2);
return worldInfo;
}
catch (Exception var4)
{
var4.printStackTrace();
}
}
return null;
}
/**
* Saves the given World Info with the given NBTTagCompound as the Player.
*/
public void saveWorldInfoWithPlayer(WorldInfo par1WorldInfo, NBTTagCompound par2NBTTagCompound)
{
NBTTagCompound var3 = par1WorldInfo.cloneNBTCompound(par2NBTTagCompound);
NBTTagCompound var4 = new NBTTagCompound();
var4.setTag("Data", var3);
FMLCommonHandler.instance().handleWorldDataSave(this, par1WorldInfo, var4);
try
{
File var5 = new File(this.worldDirectory, "level.dat_new");
File var6 = new File(this.worldDirectory, "level.dat_old");
File var7 = new File(this.worldDirectory, "level.dat");
CompressedStreamTools.writeCompressed(var4, new FileOutputStream(var5));
if (var6.exists())
{
var6.delete();
}
var7.renameTo(var6);
if (var7.exists())
{
var7.delete();
}
var5.renameTo(var7);
if (var5.exists())
{
var5.delete();
}
}
catch (Exception var8)
{
var8.printStackTrace();
}
}
/**
* Saves the passed in world info.
*/
public void saveWorldInfo(WorldInfo par1WorldInfo)
{
NBTTagCompound var2 = par1WorldInfo.getNBTTagCompound();
NBTTagCompound var3 = new NBTTagCompound();
var3.setTag("Data", var2);
FMLCommonHandler.instance().handleWorldDataSave(this, par1WorldInfo, var3);
try
{
File var4 = new File(this.worldDirectory, "level.dat_new");
File var5 = new File(this.worldDirectory, "level.dat_old");
File var6 = new File(this.worldDirectory, "level.dat");
CompressedStreamTools.writeCompressed(var3, new FileOutputStream(var4));
if (var5.exists())
{
var5.delete();
}
var6.renameTo(var5);
if (var6.exists())
{
var6.delete();
}
var4.renameTo(var6);
if (var4.exists())
{
var4.delete();
}
}
catch (Exception var7)
{
var7.printStackTrace();
}
}
/**
* Writes the player data to disk from the specified PlayerEntityMP.
*/
public void writePlayerData(EntityPlayer par1EntityPlayer)
{
try
{
NBTTagCompound var2 = new NBTTagCompound();
par1EntityPlayer.writeToNBT(var2);
File var3 = new File(this.playersDirectory, par1EntityPlayer.username + ".dat.tmp");
File var4 = new File(this.playersDirectory, par1EntityPlayer.username + ".dat");
CompressedStreamTools.writeCompressed(var2, new FileOutputStream(var3));
if (var4.exists())
{
var4.delete();
}
var3.renameTo(var4);
}
catch (Exception var5)
{
logger.warning("Failed to save player data for " + par1EntityPlayer.username);
}
}
/**
* Reads the player data from disk into the specified PlayerEntityMP.
*/
public void readPlayerData(EntityPlayer par1EntityPlayer)
{
NBTTagCompound var2 = this.getPlayerData(par1EntityPlayer.username);
if (var2 != null)
{
par1EntityPlayer.readFromNBT(var2);
}
}
/**
* Gets the player data for the given playername as a NBTTagCompound.
*/
public NBTTagCompound getPlayerData(String par1Str)
{
try
{
File var2 = new File(this.playersDirectory, par1Str + ".dat");
if (var2.exists())
{
return CompressedStreamTools.readCompressed(new FileInputStream(var2));
}
}
catch (Exception var3)
{
logger.warning("Failed to load player data for " + par1Str);
}
return null;
}
/**
* returns null if no saveHandler is relevent (eg. SMP)
*/
public IPlayerFileData getSaveHandler()
{
return this;
}
/**
* Returns an array of usernames for which player.dat exists for.
*/
public String[] getAvailablePlayerDat()
{
String[] var1 = this.playersDirectory.list();
for (int var2 = 0; var2 < var1.length; ++var2)
{
if (var1[var2].endsWith(".dat"))
{
var1[var2] = var1[var2].substring(0, var1[var2].length() - 4);
}
}
return var1;
}
/**
* Called to flush all changes to disk, waiting for them to complete.
*/
public void flush() {}
/**
* Gets the file location of the given map
*/
public File getMapFileFromName(String par1Str)
{
return new File(this.mapDataDir, par1Str + ".dat");
}
/**
* Returns the name of the directory where world information is saved.
*/
public String getSaveDirectoryName()
{
return this.saveDirectoryName;
}
}