public static boolean clearWorldReference(World world) { String worldname = world.getName(); if (regionfiles == null) return false; if (rafField == null) return false; ArrayList<Object> removedKeys = new ArrayList<Object>(); try { for (Object o : regionfiles.entrySet()) { Map.Entry e = (Map.Entry) o; File f = (File) e.getKey(); if (f.toString().startsWith("." + File.separator + worldname)) { SoftReference ref = (SoftReference) e.getValue(); try { RegionFile file = (RegionFile) ref.get(); if (file != null) { RandomAccessFile raf = (RandomAccessFile) rafField.get(file); raf.close(); removedKeys.add(f); } } catch (Exception ex) { ex.printStackTrace(); } } } } catch (Exception ex) { MyWorlds.log( Level.WARNING, "Exception while removing world reference for '" + worldname + "'!"); ex.printStackTrace(); } for (Object key : removedKeys) { regionfiles.remove(key); } return true; }
public static boolean init() { try { Field a = net.minecraft.server.RegionFileCache.class.getDeclaredField("a"); a.setAccessible(true); regionfiles = (HashMap) a.get(null); rafField = net.minecraft.server.RegionFile.class.getDeclaredField("c"); rafField.setAccessible(true); MyWorlds.log(Level.INFO, "Successfully bound variable to region file cache."); MyWorlds.log(Level.INFO, "File references to unloaded worlds will be cleared!"); return true; } catch (Throwable t) { MyWorlds.log(Level.WARNING, "Failed to bind to region file cache."); MyWorlds.log(Level.WARNING, "Files will stay referenced after being unloaded!"); t.printStackTrace(); return false; } }
/** * Repairs the chunk region file Returns -1 if the file had to be removed Returns -2 if we had no * access Returns -3 if file removal failed (from -1) Returns the amount of changed chunks * otherwise * * @param chunkfile * @param backupfolder * @return */ public static int repairRegion(File chunkfile, File backupfolder) { MyWorlds.log(Level.INFO, "Performing repairs on region file: " + chunkfile.getName()); RandomAccessFile raf = null; try { raf = new RandomAccessFile(chunkfile, "rw"); File backupfile = new File(backupfolder + File.separator + chunkfile.getName()); int[] locations = new int[1024]; for (int i = 0; i < 1024; i++) { locations[i] = raf.readInt(); } // Validate the data int editcount = 0; for (int i = 0; i < locations.length; i++) { int location = locations[i]; if (location == 0) continue; try { int offset = location >> 8; int size = location & 255; raf.seek((long) (offset * 4096)); int length = raf.readInt(); // Read and test the data if (length > 4096 * size) { editcount++; locations[i] = 0; MyWorlds.log(Level.WARNING, "Invalid length: " + length + " > 4096 * " + size); // Invalid length } else if (size > 0 && length > 0) { byte version = raf.readByte(); byte[] data = new byte[length - 1]; raf.read(data); ByteArrayInputStream bais = new ByteArrayInputStream(data); // Try to load it all... DataInputStream stream; if (version == 1) { stream = new DataInputStream(new GZIPInputStream(bais)); } else if (version == 2) { stream = new DataInputStream(new InflaterInputStream(bais)); } else { stream = null; // Unknown version MyWorlds.log( Level.WARNING, "Unknown region version: " + version + " (we probably need an update here!)"); } if (stream != null) { // Validate the stream and close try { NBTBase base = NBTTagCompound.b((DataInput) stream); if (base == null) { editcount++; locations[i] = 0; MyWorlds.log(Level.WARNING, "Invalid tag compount at chunk " + i); } else if (!(base instanceof NBTTagCompound)) { editcount++; locations[i] = 0; MyWorlds.log(Level.WARNING, "Invalid tag compount at chunk " + i); } } catch (Exception ex) { // Invalid. editcount++; locations[i] = 0; MyWorlds.log(Level.WARNING, "Stream " + i); ex.printStackTrace(); } stream.close(); } } } catch (Exception ex) { editcount++; locations[i] = 0; ex.printStackTrace(); } } if (editcount > 0) { if (backupfolder.mkdirs() && copy(chunkfile, backupfile)) { // Write out the new locations raf.seek(0); for (int location : locations) { raf.writeInt(location); } } else { MyWorlds.log(Level.WARNING, "Failed to make a copy of the file, no changes are made."); return -2; } } // Done. raf.close(); return editcount; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if (raf != null) raf.close(); } catch (Exception ex) { } try { chunkfile.delete(); return -1; } catch (Exception ex) { return -3; } }
public static World createWorld(String worldname, long seed) { String gen = getGeneratorPlugin(worldname); if (gen == null) { MyWorlds.log(Level.INFO, "Loading or creating world: '" + worldname + "' using seed " + seed); } else { MyWorlds.log( Level.INFO, "Loading or creating world: '" + worldname + "' using seed " + seed + " and chunk generator: '" + gen + "'"); } final int retrycount = 3; World w = null; int i = 0; ChunkGenerator cgen = null; try { if (gen != null) { cgen = getGenerator(worldname, gen); } } catch (Exception ex) { } if (gen != null && cgen == null) { MyWorlds.log( Level.SEVERE, "World '" + worldname + "' could not be loaded because the chunk generator '" + gen + "' was not found!"); return null; } WorldConfig wc = WorldConfig.get(worldname); wc.chunkGeneratorName = gen; for (i = 0; i < retrycount + 1; i++) { try { WorldCreator c = new WorldCreator(worldname); c.environment(wc.environment); c.seed(seed); c.generator(cgen); w = c.createWorld(); } catch (Exception ex) { MyWorlds.log(Level.WARNING, "World load issue: " + ex.getMessage()); } if (w != null) break; } if (w != null) { wc.updatePVP(w); // Data file is made? if (!worldExists(worldname)) { w.save(); } } if (w == null) { MyWorlds.log(Level.WARNING, "Operation failed after " + i + " retries!"); } else if (i == 1) { MyWorlds.log(Level.INFO, "Operation succeeded after 1 retry!"); } else if (i > 0) { MyWorlds.log(Level.INFO, "Operation succeeded after " + i + " retries!"); } return w; }