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}