package StevenDimDoors.mod_pocketDim.saving; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.util.FileFilters; import StevenDimDoors.mod_pocketDim.util.Point4D; import com.google.common.io.Files; public class DDSaveHandler { public static boolean loadAll() { // SenseiKiwi: Loading up our save data is not as simple as just reading files. // To properly restore dimensions, we need to make sure we always load // a dimension's parent and root before trying to load it. We'll use // topological sorting to determine the order in which to recreate the // dimension objects such that we respect those dependencies. // Links must be loaded after instantiating all the dimensions and must // be checked against our dimension blacklist. // Don't surround this code with try-catch. Our mod should crash if an error // occurs at this level, since it could lead to some nasty problems. String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; File dataDirectory = new File(basePath); // Check if the folder exists. If it doesn't, just return. if (!dataDirectory.exists()) { return true; } // Load the dimension blacklist // --insert code here-- // List any dimension data files and read each dimension DimDataProcessor reader = new DimDataProcessor(); List packedDims = new ArrayList(); FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); File[] dataFiles = dataDirectory.listFiles(dataFileFilter); for (File dataFile : dataFiles) { PackedDimData packedDim = readDimension(dataFile, reader); packedDims.add(packedDim); } List linksToUnpack = new ArrayList(); //get the grand list of all links to unpack for(PackedDimData packedDim : packedDims) { linksToUnpack.addAll(packedDim.Links); } return unpackDimData(packedDims)&&unpackLinkData(linksToUnpack); } /** * Takes a list of packedDimData and rebuilds the DimData for it * @param packedDims * @return */ public static boolean unpackDimData(List packedDims) { List unpackedDims = new ArrayList(); //Load roots for(PackedDimData packedDim : packedDims) { if(packedDim.ParentID==packedDim.ID) { PocketManager.registerPackedDimData(packedDim); unpackedDims.add(packedDim); } } packedDims.removeAll(unpackedDims); unpackedDims.clear(); //Load the pockets while(!packedDims.isEmpty()) { for(PackedDimData packedDim : packedDims) { if(PocketManager.isRegisteredInternally(packedDim.ParentID)) { PocketManager.registerPackedDimData(packedDim); unpackedDims.add(packedDim); } else { //break here gracefully } } packedDims.removeAll(unpackedDims); unpackedDims.clear(); } return true; } public static boolean unpackLinkData(List linksToUnpack) { Point3D fakePoint = new Point3D(-1,-1,-1); List unpackedLinks = new ArrayList(); /** * sort through the list, unpacking links that do not have parents. */ //TODO- what we have a loop of links? for(PackedLinkData packedLink : linksToUnpack) { if(packedLink.parent.equals(fakePoint)) { NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); DimLink link = data.createLink(packedLink.source, packedLink.tail.linkType, packedLink.orientation); Point4D destination = packedLink.tail.destination; if(destination!=null) { PocketManager.getDimensionData(destination.getDimension()).setDestination(link, destination.getX(),destination.getY(),destination.getZ()); } unpackedLinks.add(packedLink); } } linksToUnpack.removeAll(unpackedLinks); //unpack remaining children while(!linksToUnpack.isEmpty()) { for(PackedLinkData packedLink : linksToUnpack) { NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); if(data.getLink(packedLink.parent)!=null) { data.createChildLink(packedLink.source.getX(), packedLink.source.getY(), packedLink.source.getZ(), data.getLink(packedLink.parent)); } unpackedLinks.add(packedLink); } linksToUnpack.removeAll(unpackedLinks); } return true; } private static PackedDimData readDimension(File dataFile, DimDataProcessor reader) { try { return reader.readFromFile(dataFile); } catch (Exception e) { System.err.println("Could not read dimension data from: " + dataFile.getAbsolutePath()); System.err.println("The following error occurred:"); printException(e, false); return null; } } public static boolean saveAll(Iterable> dimensions) throws IOException { // Create the data directory for our dimensions // Don't catch exceptions here. If we can't create this folder, // the mod should crash to let the user know early on. String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; File basePathFile = new File(basePath); Files.createParentDirs(basePathFile); basePathFile.mkdir(); FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); //TODO Deal with temp files correctly File[] dataFiles = basePathFile.listFiles(dataFileFilter); for (File dataFile : dataFiles) { dataFile.delete(); } basePathFile = null; basePath += "dim_"; boolean succeeded = true; DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { succeeded &= writeDimension(dimension, writer, basePath); } return succeeded; } private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath) { try { File tempFile = new File(basePath + (dimension.name() + ".tmp")); File saveFile = new File(basePath + (dimension.name() + ".txt")); writer.writeToFile(tempFile, dimension.pack()); saveFile.delete(); tempFile.renameTo(saveFile); return true; } catch (Exception e) { System.err.println("Could not save data for dimension #" + dimension.name() + ". The following error occurred:"); printException(e, true); return false; } } private static void printException(Exception e, boolean verbose) { if (e.getCause() == null) { if (verbose) { e.printStackTrace(); } else { System.err.println(e.getMessage()); } } else { System.out.println(e.getMessage()); System.err.println("Caused by an underlying error:"); if (verbose) { e.getCause().printStackTrace(); } else { System.err.println(e.getCause().getMessage()); } } } //TODO - make this more robust public static DungeonData unpackDungeonData(PackedDungeonData packedDungeon) { DungeonPack pack; DungeonType type; for(DungeonData data : DungeonHelper.instance().getRegisteredDungeons()) { if(data.schematicName().equals(packedDungeon.SchematicName)) { //return data; } } return null; } }