    001package net.minecraft.world.chunk.storage;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.io.DataInputStream;
    006import java.io.DataOutputStream;
    007import java.io.File;
    008import java.io.IOException;
    009import java.util.ArrayList;
    010import java.util.Collection;
    011import java.util.Collections;
    012import java.util.Iterator;
    013import java.util.List;
    014import net.minecraft.client.AnvilConverterException;
    015import net.minecraft.nbt.CompressedStreamTools;
    016import net.minecraft.nbt.NBTTagCompound;
    017import net.minecraft.server.MinecraftServer;
    018import net.minecraft.util.IProgressUpdate;
    019import net.minecraft.util.MathHelper;
    020import net.minecraft.world.WorldType;
    021import net.minecraft.world.biome.BiomeGenBase;
    022import net.minecraft.world.biome.WorldChunkManager;
    023import net.minecraft.world.biome.WorldChunkManagerHell;
    024import net.minecraft.world.storage.ISaveHandler;
    025import net.minecraft.world.storage.SaveFormatComparator;
    026import net.minecraft.world.storage.SaveFormatOld;
    027import net.minecraft.world.storage.WorldInfo;
    028
    029public class AnvilSaveConverter extends SaveFormatOld
    030{
    031    public AnvilSaveConverter(File par1File)
    032    {
    033        super(par1File);
    034    }
    035
    036    @SideOnly(Side.CLIENT)
    037    public List getSaveList() throws AnvilConverterException
    038    {
    039        if (this.savesDirectory != null && this.savesDirectory.exists() && this.savesDirectory.isDirectory())
    040        {
    041            ArrayList arraylist = new ArrayList();
    042            File[] afile = this.savesDirectory.listFiles();
    043            File[] afile1 = afile;
    044            int i = afile.length;
    045
    046            for (int j = 0; j < i; ++j)
    047            {
    048                File file1 = afile1[j];
    049
    050                if (file1.isDirectory())
    051                {
    052                    String s = file1.getName();
    053                    WorldInfo worldinfo = this.getWorldInfo(s);
    054
    055                    if (worldinfo != null && (worldinfo.getSaveVersion() == 19132 || worldinfo.getSaveVersion() == 19133))
    056                    {
    057                        boolean flag = worldinfo.getSaveVersion() != this.getSaveVersion();
    058                        String s1 = worldinfo.getWorldName();
    059
    060                        if (s1 == null || MathHelper.stringNullOrLengthZero(s1))
    061                        {
    062                            s1 = s;
    063                        }
    064
    065                        long k = 0L;
    066                        arraylist.add(new SaveFormatComparator(s, s1, worldinfo.getLastTimePlayed(), k, worldinfo.getGameType(), flag, worldinfo.isHardcoreModeEnabled(), worldinfo.areCommandsAllowed()));
    067                    }
    068                }
    069            }
    070
    071            return arraylist;
    072        }
    073        else
    074        {
    075            throw new AnvilConverterException("Unable to read or access folder where game worlds are saved!");
    076        }
    077    }
    078
    079    protected int getSaveVersion()
    080    {
    081        return 19133;
    082    }
    083
    084    public void flushCache()
    085    {
    086        RegionFileCache.clearRegionFileReferences();
    087    }
    088
    089    /**
    090     * Returns back a loader for the specified save directory
    091     */
    092    public ISaveHandler getSaveLoader(String par1Str, boolean par2)
    093    {
    094        return new AnvilSaveHandler(this.savesDirectory, par1Str, par2);
    095    }
    096
    097    /**
    098     * Checks if the save directory uses the old map format
    099     */
    100    public boolean isOldMapFormat(String par1Str)
    101    {
    102        WorldInfo worldinfo = this.getWorldInfo(par1Str);
    103        return worldinfo != null && worldinfo.getSaveVersion() != this.getSaveVersion();
    104    }
    105
    106    /**
    107     * Converts the specified map to the new map format. Args: worldName, loadingScreen
    108     */
    109    public boolean convertMapFormat(String par1Str, IProgressUpdate par2IProgressUpdate)
    110    {
    111        par2IProgressUpdate.setLoadingProgress(0);
    112        ArrayList arraylist = new ArrayList();
    113        ArrayList arraylist1 = new ArrayList();
    114        ArrayList arraylist2 = new ArrayList();
    115        File file1 = new File(this.savesDirectory, par1Str);
    116        File file2 = new File(file1, "DIM-1");
    117        File file3 = new File(file1, "DIM1");
    118        MinecraftServer.getServer().getLogAgent().logInfo("Scanning folders...");
    119        this.addRegionFilesToCollection(file1, arraylist);
    120
    121        if (file2.exists())
    122        {
    123            this.addRegionFilesToCollection(file2, arraylist1);
    124        }
    125
    126        if (file3.exists())
    127        {
    128            this.addRegionFilesToCollection(file3, arraylist2);
    129        }
    130
    131        int i = arraylist.size() + arraylist1.size() + arraylist2.size();
    132        MinecraftServer.getServer().getLogAgent().logInfo("Total conversion count is " + i);
    133        WorldInfo worldinfo = this.getWorldInfo(par1Str);
    134        Object object = null;
    135
    136        if (worldinfo.getTerrainType() == WorldType.FLAT)
    137        {
    138            object = new WorldChunkManagerHell(BiomeGenBase.plains, 0.5F, 0.5F);
    139        }
    140        else
    141        {
    142            object = new WorldChunkManager(worldinfo.getSeed(), worldinfo.getTerrainType());
    143        }
    144
    145        this.convertFile(new File(file1, "region"), arraylist, (WorldChunkManager)object, 0, i, par2IProgressUpdate);
    146        this.convertFile(new File(file2, "region"), arraylist1, new WorldChunkManagerHell(BiomeGenBase.hell, 1.0F, 0.0F), arraylist.size(), i, par2IProgressUpdate);
    147        this.convertFile(new File(file3, "region"), arraylist2, new WorldChunkManagerHell(BiomeGenBase.sky, 0.5F, 0.0F), arraylist.size() + arraylist1.size(), i, par2IProgressUpdate);
    148        worldinfo.setSaveVersion(19133);
    149
    150        if (worldinfo.getTerrainType() == WorldType.DEFAULT_1_1)
    151        {
    152            worldinfo.setTerrainType(WorldType.DEFAULT);
    153        }
    154
    155        this.createFile(par1Str);
    156        ISaveHandler isavehandler = this.getSaveLoader(par1Str, false);
    157        isavehandler.saveWorldInfo(worldinfo);
    158        return true;
    159    }
    160
    161    /**
    162     * par: filename for the level.dat_mcr backup
    163     */
    164    private void createFile(String par1Str)
    165    {
    166        File file1 = new File(this.savesDirectory, par1Str);
    167
    168        if (!file1.exists())
    169        {
    170            System.out.println("Warning: Unable to create level.dat_mcr backup");
    171        }
    172        else
    173        {
    174            File file2 = new File(file1, "level.dat");
    175
    176            if (!file2.exists())
    177            {
    178                System.out.println("Warning: Unable to create level.dat_mcr backup");
    179            }
    180            else
    181            {
    182                File file3 = new File(file1, "level.dat_mcr");
    183
    184                if (!file2.renameTo(file3))
    185                {
    186                    System.out.println("Warning: Unable to create level.dat_mcr backup");
    187                }
    188            }
    189        }
    190    }
    191
    192    private void convertFile(File par1File, Iterable par2Iterable, WorldChunkManager par3WorldChunkManager, int par4, int par5, IProgressUpdate par6IProgressUpdate)
    193    {
    194        Iterator iterator = par2Iterable.iterator();
    195
    196        while (iterator.hasNext())
    197        {
    198            File file2 = (File)iterator.next();
    199            this.convertChunks(par1File, file2, par3WorldChunkManager, par4, par5, par6IProgressUpdate);
    200            ++par4;
    201            int k = (int)Math.round(100.0D * (double)par4 / (double)par5);
    202            par6IProgressUpdate.setLoadingProgress(k);
    203        }
    204    }
    205
    206    /**
    207     * copies a 32x32 chunk set from par2File to par1File, via AnvilConverterData
    208     */
    209    private void convertChunks(File par1File, File par2File, WorldChunkManager par3WorldChunkManager, int par4, int par5, IProgressUpdate par6IProgressUpdate)
    210    {
    211        try
    212        {
    213            String s = par2File.getName();
    214            RegionFile regionfile = new RegionFile(par2File);
    215            RegionFile regionfile1 = new RegionFile(new File(par1File, s.substring(0, s.length() - ".mcr".length()) + ".mca"));
    216
    217            for (int k = 0; k < 32; ++k)
    218            {
    219                int l;
    220
    221                for (l = 0; l < 32; ++l)
    222                {
    223                    if (regionfile.isChunkSaved(k, l) && !regionfile1.isChunkSaved(k, l))
    224                    {
    225                        DataInputStream datainputstream = regionfile.getChunkDataInputStream(k, l);
    226
    227                        if (datainputstream == null)
    228                        {
    229                            MinecraftServer.getServer().getLogAgent().logWarning("Failed to fetch input stream");
    230                        }
    231                        else
    232                        {
    233                            NBTTagCompound nbttagcompound = CompressedStreamTools.read(datainputstream);
    234                            datainputstream.close();
    235                            NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("Level");
    236                            AnvilConverterData anvilconverterdata = ChunkLoader.load(nbttagcompound1);
    237                            NBTTagCompound nbttagcompound2 = new NBTTagCompound();
    238                            NBTTagCompound nbttagcompound3 = new NBTTagCompound();
    239                            nbttagcompound2.setTag("Level", nbttagcompound3);
    240                            ChunkLoader.convertToAnvilFormat(anvilconverterdata, nbttagcompound3, par3WorldChunkManager);
    241                            DataOutputStream dataoutputstream = regionfile1.getChunkDataOutputStream(k, l);
    242                            CompressedStreamTools.write(nbttagcompound2, dataoutputstream);
    243                            dataoutputstream.close();
    244                        }
    245                    }
    246                }
    247
    248                l = (int)Math.round(100.0D * (double)(par4 * 1024) / (double)(par5 * 1024));
    249                int i1 = (int)Math.round(100.0D * (double)((k + 1) * 32 + par4 * 1024) / (double)(par5 * 1024));
    250
    251                if (i1 > l)
    252                {
    253                    par6IProgressUpdate.setLoadingProgress(i1);
    254                }
    255            }
    256
    257            regionfile.close();
    258            regionfile1.close();
    259        }
    260        catch (IOException ioexception)
    261        {
    262            ioexception.printStackTrace();
    263        }
    264    }
    265
    266    /**
    267     * filters the files in the par1 directory, and adds them to the par2 collections
    268     */
    269    private void addRegionFilesToCollection(File par1File, Collection par2Collection)
    270    {
    271        File file2 = new File(par1File, "region");
    272        File[] afile = file2.listFiles(new AnvilSaveConverterFileFilter(this));
    273
    274        if (afile != null)
    275        {
    276            Collections.addAll(par2Collection, afile);
    277        }
    278    }
    279}