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}