private void ScrubTerrainFiles() { // Build a list of all terrain files in user storage. // For each world in local storage (all three bins) // get the XmlWorldData file // from the XmlWorldData file, get the terrain filename // remove that filename from the list // // Any terrain filenames still on the list should be deleted // since they're no longer referenced by any files. string[] terrainFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.TerrainPath, @"*.raw", StorageSource.UserSpace); // If nothing to scrub, just return. if (terrainFiles == null) { return; } string[] undoFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.UnDoPath, @"*.Xml", StorageSource.UserSpace); string[] myWorldsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.MyWorldsPath, @"*.Xml", StorageSource.UserSpace); string[] starterWorldsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.BuiltInWorldsPath, @"*.Xml", StorageSource.TitleSpace); string[] downloadsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.DownloadsPath, @"*.Xml", StorageSource.UserSpace); /// Undo/Resume files. We might have to fall back on these if the user deletes the /// world they are editing and then back back to it. if (undoFiles != null) { for (int i = 0; i < undoFiles.Length; ++i) { string filename = undoFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null) { continue; } if (xmlWorldData.xmlTerrainData2 != null) { string terrainName = Path.Combine(Storage4.UserLocation, BokuGame.Settings.MediaPath, xmlWorldData.xmlTerrainData2.virtualMapFile); for (int j = 0; j < terrainFiles.Length; ++j) { if (terrainName == terrainFiles[j]) { // Remove this file. terrainFiles[j] = null; break; } } } } } // MyWorlds if (myWorldsFiles != null) { for (int i = 0; i < myWorldsFiles.Length; ++i) { string filename = myWorldsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null) { continue; } if (xmlWorldData.xmlTerrainData2 != null) { string terrainName = Path.Combine(Storage4.UserLocation, BokuGame.Settings.MediaPath, xmlWorldData.xmlTerrainData2.virtualMapFile); for (int j = 0; j < terrainFiles.Length; ++j) { if (terrainName == terrainFiles[j]) { // Remove this file. terrainFiles[j] = null; break; } } } } } // BuiltInWorlds if (starterWorldsFiles != null) { for (int i = 0; i < starterWorldsFiles.Length; ++i) { try { string filename = starterWorldsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null) { continue; } if (xmlWorldData.xmlTerrainData2 != null) { string terrainName = Path.Combine(Storage4.UserLocation, BokuGame.Settings.MediaPath, xmlWorldData.xmlTerrainData2.virtualMapFile); for (int j = 0; j < terrainFiles.Length; ++j) { if (terrainName == terrainFiles[j]) { // Remove this file. terrainFiles[j] = null; break; } } } } catch { } } } // Downloads if (downloadsFiles != null) { for (int i = 0; i < downloadsFiles.Length; ++i) { string filename = downloadsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null) { continue; } if (xmlWorldData.xmlTerrainData2 != null) { string terrainName = Path.Combine(Storage4.UserLocation, BokuGame.Settings.MediaPath, xmlWorldData.xmlTerrainData2.virtualMapFile); for (int j = 0; j < terrainFiles.Length; ++j) { if (terrainName == terrainFiles[j]) { // Remove this file. terrainFiles[j] = null; break; } } } } } int deleteCount = 0; // Now, anything that's left in the list should be fair game for deletion. for (int i = 0; i < terrainFiles.Length; i++) { if (terrainFiles[i] != null) { if (Storage4.FileExists(terrainFiles[i], StorageSource.UserSpace)) { if (Storage4.Delete(terrainFiles[i])) { deleteCount += 1; } } } } //System.Diagnostics.Debug.WriteLine(String.Format("Scrubbed {0} terrain files", deleteCount)); } // end of ScrubTerrainFiles()
/// <summary> /// Delete a level from the local system. Returns false if not yet initialized. /// </summary> /// <param name="worldId"></param> /// <param name="callback"></param> /// <param name="param"></param> /// <returns></returns> public bool StartDeletingLevel( Guid worldId, Genres bucket, BokuAsyncCallback callback, object param) { bool deleted = false; bucket &= Genres.SharableBins; // Verify exactly one bucket is specified Debug.Assert(bucket != 0); Debug.Assert((int)bucket == int.MinValue || MyMath.IsPowerOfTwo((int)bucket)); string worldFilename = null; string stuffFilename = null; string thumbFilename = null; LevelMetadata record = null; string stuffPath = String.Empty; string worldPath = String.Empty; if (0 != (bucket & Genres.MyWorlds)) { stuffPath = BokuGame.MyWorldsStuffPath; worldPath = BokuGame.MyWorldsPath; } else if (0 != (bucket & Genres.Downloads)) { stuffPath = BokuGame.DownloadsStuffPath; worldPath = BokuGame.DownloadsPath; } lock (Synch) { for (int i = 0; i < allLevels.Count; ++i) { record = allLevels[i]; if (record.WorldId == worldId && (record.Genres & bucket) == bucket) { worldFilename = Path.Combine(BokuGame.Settings.MediaPath, worldPath + worldId.ToString() + @".Xml"); stuffFilename = Path.Combine(BokuGame.Settings.MediaPath, stuffPath + worldId.ToString() + @".Xml"); thumbFilename = Path.Combine(BokuGame.Settings.MediaPath, worldPath + worldId.ToString()); // Need to get the terrain file before we delete the main file. BUT the terrain should be // deleted after, otherwise the usage test will find the main file and always thing that // the terrain file is in use. string terrainFilename = null; try { // Only delete terrain file if no longer referenced. XmlWorldData xmlWorldData = XmlWorldData.Load(worldFilename, XnaStorageHelper.Instance); terrainFilename = xmlWorldData.xmlTerrainData2.virtualMapFile; } catch { } // Note : Delete() handles non-existent files just fine. Storage4.Delete(worldFilename); Storage4.Delete(stuffFilename); Storage4.Delete(thumbFilename + @".dds"); Storage4.Delete(thumbFilename + @".jpg"); Storage4.Delete(thumbFilename + @".png"); // Only deletes terrain file if no other world is using it. (including autosaves) DeleteTerrainFile(terrainFilename); LevelMetadata level = allLevels[i]; allLevels.RemoveAt(i); LevelRemoved_Synched(level); deleted = true; break; } } } AsyncResult result = new AsyncResult(); result.Success = deleted; result.Param = param; result.Seconds = 0; if (callback != null) { callback(result); } return(deleted); }
} // end of ScrubTerrainFiles() /// <summary> /// Deletes the given terrain file but only after verifying that no world is using it. /// It any world is found that is using the file then it is not deleted. /// /// Note this still isn't perfect since when a level is deleted, the terrain file may still be left /// in the undo stack and hence not deleted. No biggy. It's better than deleting too much and it's /// much quicker than the above ScrubTerrainFiles(). /// </summary> /// <param name="terrainFile"></param> void DeleteTerrainFile(string terrainFile) { string[] undoFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.UnDoPath, @"*.Xml", StorageSource.UserSpace); string[] myWorldsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.MyWorldsPath, @"*.Xml", StorageSource.UserSpace); string[] starterWorldsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.BuiltInWorldsPath, @"*.Xml", StorageSource.TitleSpace); string[] downloadsFiles = Storage4.GetFiles(BokuGame.Settings.MediaPath + BokuGame.DownloadsPath, @"*.Xml", StorageSource.UserSpace); /// Undo/Resume files. We might have to fall back on these if the user deletes the /// world they are editing and then back back to it. if (undoFiles != null) { for (int i = 0; i < undoFiles.Length; ++i) { string filename = undoFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null || xmlWorldData.xmlTerrainData2 == null) { continue; } if (xmlWorldData.xmlTerrainData2.virtualMapFile == terrainFile) { // Found it, don't delete. return; } } } // MyWorlds if (myWorldsFiles != null) { for (int i = 0; i < myWorldsFiles.Length; ++i) { string filename = myWorldsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null || xmlWorldData.xmlTerrainData2 == null) { continue; } if (xmlWorldData.xmlTerrainData2.virtualMapFile == terrainFile) { // Found it, don't delete. return; } } } // BuiltInWorlds if (starterWorldsFiles != null) { for (int i = 0; i < starterWorldsFiles.Length; ++i) { try { string filename = starterWorldsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null || xmlWorldData.xmlTerrainData2 == null) { continue; } if (xmlWorldData.xmlTerrainData2.virtualMapFile == terrainFile) { // Found it, don't delete. return; } } catch { } } } // Downloads if (downloadsFiles != null) { for (int i = 0; i < downloadsFiles.Length; ++i) { string filename = downloadsFiles[i]; XmlWorldData xmlWorldData = XmlWorldData.Load(filename, XnaStorageHelper.Instance); if (xmlWorldData == null || xmlWorldData.xmlTerrainData2 == null) { continue; } if (xmlWorldData.xmlTerrainData2.virtualMapFile == terrainFile) { // Found it, don't delete. return; } } } // Nothing was found using this terrain file so we can delete it. try { terrainFile = Path.Combine(BokuGame.Settings.MediaPath, terrainFile); Storage4.Delete(terrainFile); } catch (Exception e) { if (e != null) { } } } // end of DeleteTerrainFile()