package net.minecraft.world.chunk.storage;
import com.google.common.collect.Lists;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import net.minecraft.server.MinecraftServer;
public class RegionFile
{
private static final byte[] emptySector = new byte[4096];
private final File fileName;
private RandomAccessFile dataFile;
private final int[] offsets = new int[1024];
private final int[] chunkTimestamps = new int[1024];
private List sectorFree;
/** McRegion sizeDelta */
private int sizeDelta;
private long lastModified;
private static final String __OBFID = "CL_00000381";
public RegionFile(File p_i2001_1_)
{
this.fileName = p_i2001_1_;
this.sizeDelta = 0;
try
{
if (p_i2001_1_.exists())
{
this.lastModified = p_i2001_1_.lastModified();
}
this.dataFile = new RandomAccessFile(p_i2001_1_, "rw");
int var2;
if (this.dataFile.length() < 4096L)
{
for (var2 = 0; var2 < 1024; ++var2)
{
this.dataFile.writeInt(0);
}
for (var2 = 0; var2 < 1024; ++var2)
{
this.dataFile.writeInt(0);
}
this.sizeDelta += 8192;
}
if ((this.dataFile.length() & 4095L) != 0L)
{
for (var2 = 0; (long)var2 < (this.dataFile.length() & 4095L); ++var2)
{
this.dataFile.write(0);
}
}
var2 = (int)this.dataFile.length() / 4096;
this.sectorFree = Lists.newArrayListWithCapacity(var2);
int var3;
for (var3 = 0; var3 < var2; ++var3)
{
this.sectorFree.add(Boolean.valueOf(true));
}
this.sectorFree.set(0, Boolean.valueOf(false));
this.sectorFree.set(1, Boolean.valueOf(false));
this.dataFile.seek(0L);
int var4;
for (var3 = 0; var3 < 1024; ++var3)
{
var4 = this.dataFile.readInt();
this.offsets[var3] = var4;
if (var4 != 0 && (var4 >> 8) + (var4 & 255) <= this.sectorFree.size())
{
for (int var5 = 0; var5 < (var4 & 255); ++var5)
{
this.sectorFree.set((var4 >> 8) + var5, Boolean.valueOf(false));
}
}
}
for (var3 = 0; var3 < 1024; ++var3)
{
var4 = this.dataFile.readInt();
this.chunkTimestamps[var3] = var4;
}
}
catch (IOException var6)
{
var6.printStackTrace();
}
}
/**
* args: x, y - get uncompressed chunk stream from the region file
*/
public synchronized DataInputStream getChunkDataInputStream(int p_76704_1_, int p_76704_2_)
{
if (this.outOfBounds(p_76704_1_, p_76704_2_))
{
return null;
}
else
{
try
{
int var3 = this.getOffset(p_76704_1_, p_76704_2_);
if (var3 == 0)
{
return null;
}
else
{
int var4 = var3 >> 8;
int var5 = var3 & 255;
if (var4 + var5 > this.sectorFree.size())
{
return null;
}
else
{
this.dataFile.seek((long)(var4 * 4096));
int var6 = this.dataFile.readInt();
if (var6 > 4096 * var5)
{
return null;
}
else if (var6 <= 0)
{
return null;
}
else
{
byte var7 = this.dataFile.readByte();
byte[] var8;
if (var7 == 1)
{
var8 = new byte[var6 - 1];
this.dataFile.read(var8);
return new DataInputStream(new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(var8))));
}
else if (var7 == 2)
{
var8 = new byte[var6 - 1];
this.dataFile.read(var8);
return new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(var8))));
}
else
{
return null;
}
}
}
}
}
catch (IOException var9)
{
return null;
}
}
}
/**
* args: x, z - get an output stream used to write chunk data, data is on disk when the returned stream is closed
*/
public DataOutputStream getChunkDataOutputStream(int p_76710_1_, int p_76710_2_)
{
return this.outOfBounds(p_76710_1_, p_76710_2_) ? null : new DataOutputStream(new DeflaterOutputStream(new RegionFile.ChunkBuffer(p_76710_1_, p_76710_2_)));
}
/**
* args: x, z, data, length - write chunk data at (x, z) to disk
*/
protected synchronized void write(int p_76706_1_, int p_76706_2_, byte[] p_76706_3_, int p_76706_4_)
{
try
{
int var5 = this.getOffset(p_76706_1_, p_76706_2_);
int var6 = var5 >> 8;
int var7 = var5 & 255;
int var8 = (p_76706_4_ + 5) / 4096 + 1;
if (var8 >= 256)
{
return;
}
if (var6 != 0 && var7 == var8)
{
this.write(var6, p_76706_3_, p_76706_4_);
}
else
{
int var9;
for (var9 = 0; var9 < var7; ++var9)
{
this.sectorFree.set(var6 + var9, Boolean.valueOf(true));
}
var9 = this.sectorFree.indexOf(Boolean.valueOf(true));
int var10 = 0;
int var11;
if (var9 != -1)
{
for (var11 = var9; var11 < this.sectorFree.size(); ++var11)
{
if (var10 != 0)
{
if (((Boolean)this.sectorFree.get(var11)).booleanValue())
{
++var10;
}
else
{
var10 = 0;
}
}
else if (((Boolean)this.sectorFree.get(var11)).booleanValue())
{
var9 = var11;
var10 = 1;
}
if (var10 >= var8)
{
break;
}
}
}
if (var10 >= var8)
{
var6 = var9;
this.setOffset(p_76706_1_, p_76706_2_, var9 << 8 | var8);
for (var11 = 0; var11 < var8; ++var11)
{
this.sectorFree.set(var6 + var11, Boolean.valueOf(false));
}
this.write(var6, p_76706_3_, p_76706_4_);
}
else
{
this.dataFile.seek(this.dataFile.length());
var6 = this.sectorFree.size();
for (var11 = 0; var11 < var8; ++var11)
{
this.dataFile.write(emptySector);
this.sectorFree.add(Boolean.valueOf(false));
}
this.sizeDelta += 4096 * var8;
this.write(var6, p_76706_3_, p_76706_4_);
this.setOffset(p_76706_1_, p_76706_2_, var6 << 8 | var8);
}
}
this.setChunkTimestamp(p_76706_1_, p_76706_2_, (int)(MinecraftServer.getCurrentTimeMillis() / 1000L));
}
catch (IOException var12)
{
var12.printStackTrace();
}
}
/**
* args: sectorNumber, data, length - write the chunk data to this RegionFile
*/
private void write(int p_76712_1_, byte[] p_76712_2_, int p_76712_3_) throws IOException
{
this.dataFile.seek((long)(p_76712_1_ * 4096));
this.dataFile.writeInt(p_76712_3_ + 1);
this.dataFile.writeByte(2);
this.dataFile.write(p_76712_2_, 0, p_76712_3_);
}
/**
* args: x, z - check region bounds
*/
private boolean outOfBounds(int p_76705_1_, int p_76705_2_)
{
return p_76705_1_ < 0 || p_76705_1_ >= 32 || p_76705_2_ < 0 || p_76705_2_ >= 32;
}
/**
* args: x, y - get chunk's offset in region file
*/
private int getOffset(int p_76707_1_, int p_76707_2_)
{
return this.offsets[p_76707_1_ + p_76707_2_ * 32];
}
/**
* args: x, z, - true if chunk has been saved / converted
*/
public boolean isChunkSaved(int p_76709_1_, int p_76709_2_)
{
return this.getOffset(p_76709_1_, p_76709_2_) != 0;
}
/**
* args: x, z, offset - sets the chunk's offset in the region file
*/
private void setOffset(int p_76711_1_, int p_76711_2_, int p_76711_3_) throws IOException
{
this.offsets[p_76711_1_ + p_76711_2_ * 32] = p_76711_3_;
this.dataFile.seek((long)((p_76711_1_ + p_76711_2_ * 32) * 4));
this.dataFile.writeInt(p_76711_3_);
}
/**
* args: x, z, timestamp - sets the chunk's write timestamp
*/
private void setChunkTimestamp(int p_76713_1_, int p_76713_2_, int p_76713_3_) throws IOException
{
this.chunkTimestamps[p_76713_1_ + p_76713_2_ * 32] = p_76713_3_;
this.dataFile.seek((long)(4096 + (p_76713_1_ + p_76713_2_ * 32) * 4));
this.dataFile.writeInt(p_76713_3_);
}
/**
* close this RegionFile and prevent further writes
*/
public void close() throws IOException
{
if (this.dataFile != null)
{
this.dataFile.close();
}
}
class ChunkBuffer extends ByteArrayOutputStream
{
private int chunkX;
private int chunkZ;
private static final String __OBFID = "CL_00000382";
public ChunkBuffer(int p_i2000_2_, int p_i2000_3_)
{
super(8096);
this.chunkX = p_i2000_2_;
this.chunkZ = p_i2000_3_;
}
public void close() throws IOException
{
RegionFile.this.write(this.chunkX, this.chunkZ, this.buf, this.count);
}
}
}