From eb9781b339287625432494e5793cf6bde820b587 Mon Sep 17 00:00:00 2001 From: MaxED Date: Wed, 15 Oct 2014 08:36:17 +0000 Subject: [PATCH] Optimization, PK3: approximately 2x performance increase during background resource loading (~7 seconds vs ~16 seconds in r2083, tested on Enjay's Genetech MAP01). Fixed, PK7: fixed a potential crash when using several PK7 resources with overlapping files. --- Source/Core/Data/DataManager.cs | 8 +- Source/Core/Data/PK3FileImage.cs | 2 +- Source/Core/Data/PK3Reader.cs | 139 +++++++++++++++++++------------ 3 files changed, 95 insertions(+), 54 deletions(-) diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 5a88e727..0cabafc2 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -642,6 +642,12 @@ namespace CodeImp.DoomBuilder.Data // Timing if(loadfinishtime == 0) { + //mxd. Release PK3 files + foreach (DataReader reader in containers) + { + if (reader is PK3Reader) (reader as PK3Reader).BathMode = false; + } + loadfinishtime = Clock.CurrentTime; float deltatimesec = (loadfinishtime - loadstarttime) / 1000.0f; General.WriteLogLine("Resources loading took " + deltatimesec.ToString("########0.00") + " seconds"); @@ -1408,7 +1414,7 @@ namespace CodeImp.DoomBuilder.Data } if (actors.Count == 0) - General.ErrorLogger.Add(ErrorType.Warning, "Warning: unable to find any DECORATE actors definition!"); + General.ErrorLogger.Add(ErrorType.Warning, "Warning: unable to find any DECORATE actor definitions!"); return actors; } diff --git a/Source/Core/Data/PK3FileImage.cs b/Source/Core/Data/PK3FileImage.cs index 3f15b746..f9edf3e1 100644 --- a/Source/Core/Data/PK3FileImage.cs +++ b/Source/Core/Data/PK3FileImage.cs @@ -74,7 +74,7 @@ namespace CodeImp.DoomBuilder.Data { // Load file data if(bitmap != null) bitmap.Dispose(); bitmap = null; - MemoryStream filedata = datareader.ExtractFile(fullName); //mxd + MemoryStream filedata = datareader.LoadFile(fullName); //mxd // Get a reader for the data IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette); diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs index bb827cc8..e68f7e26 100644 --- a/Source/Core/Data/PK3Reader.cs +++ b/Source/Core/Data/PK3Reader.cs @@ -32,9 +32,17 @@ namespace CodeImp.DoomBuilder.Data { #region ================== Variables - private DirectoryFilesList files; - private ArchiveType archiveType; //mxd - private static Dictionary sevenZipEntries; //mxd + private readonly DirectoryFilesList files; + private IArchive archive; //mxd + private readonly ArchiveType archivetype; //mxd + private readonly Dictionary sevenzipentries; //mxd + private bool bathmode = true; //mxd + + #endregion + + #region ================== Properties (mxd) + + public bool BathMode { get { return bathmode; } set { bathmode = value; UpdateArchive(bathmode); } } #endregion @@ -51,35 +59,38 @@ namespace CodeImp.DoomBuilder.Data // Make list of all files List fileentries = new List(); - //mxd - IArchive archive = ArchiveFactory.Open(location.location); - archiveType = archive.Type; + // Create archive + archive = ArchiveFactory.Open(location.location, Options.KeepStreamsOpen); + archivetype = archive.Type; - if (archive.Type == ArchiveType.SevenZip) { //random access of 7z archives works TERRIBLY slow in SharpCompress - sevenZipEntries = new Dictionary(StringComparer.Ordinal); + // Random access of 7z archives works TERRIBLY slow in SharpCompress + if(archivetype == ArchiveType.SevenZip) + { + sevenzipentries = new Dictionary(StringComparer.Ordinal); IReader reader = archive.ExtractAllEntries(); - while (reader.MoveToNextEntry()) { - if (!reader.Entry.IsDirectory) { - MemoryStream s = new MemoryStream(); - reader.WriteEntryTo(s); - sevenZipEntries.Add(reader.Entry.FilePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), s.ToArray()); - fileentries.Add(new DirectoryFileEntry(reader.Entry.FilePath)); - } - } - //archive.Dispose(); - //archive = null; + while(reader.MoveToNextEntry()) + { + if(reader.Entry.IsDirectory) continue; - } else { - foreach (IEntry entry in archive.Entries) { - if (!entry.IsDirectory) - fileentries.Add(new DirectoryFileEntry(entry.FilePath)); + MemoryStream s = new MemoryStream(); + reader.WriteEntryTo(s); + sevenzipentries.Add(reader.Entry.FilePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), s.ToArray()); + fileentries.Add(new DirectoryFileEntry(reader.Entry.FilePath)); + } + + archive.Dispose(); + archive = null; + } + else + { + foreach(IArchiveEntry entry in archive.Entries) + { + if(entry.IsDirectory) continue; + fileentries.Add(new DirectoryFileEntry(entry.FilePath)); } } - archive.Dispose(); - archive = null; - // Make files list files = new DirectoryFilesList(fileentries); @@ -97,13 +108,35 @@ namespace CodeImp.DoomBuilder.Data if(!isdisposed) { General.WriteLogLine("Closing " + Path.GetExtension(location.location).ToUpper().Replace(".", "") + " resource '" + location.location + "'"); - //if(archive != null) archive.Dispose(); //mxd + + //mxd + if(archive != null) + { + archive.Dispose(); + archive = null; + } // Done base.Dispose(); } } + //mxd + private void UpdateArchive(bool enable) + { + if(archivetype == ArchiveType.SevenZip) return; + + if (enable && archive == null) + { + archive = ArchiveFactory.Open(location.location, Options.KeepStreamsOpen); + } + else if(!enable && !bathmode && archive != null) + { + archive.Dispose(); + archive = null; + } + } + #endregion #region ================== Textures @@ -349,7 +382,7 @@ namespace CodeImp.DoomBuilder.Data { string title = Path.GetFileNameWithoutExtension(beginswith); string ext = Path.GetExtension(beginswith); - if(ext.Length > 1) ext = ext.Substring(1); else ext = ""; + ext = (!string.IsNullOrEmpty(ext) && ext.Length > 1 ? ext.Substring(1) : ""); return files.GetFirstFile(path, title, subfolders, ext); } @@ -358,32 +391,40 @@ namespace CodeImp.DoomBuilder.Data internal override MemoryStream LoadFile(string filename) { MemoryStream filedata = null; - - //mxd - if (archiveType == ArchiveType.SevenZip) { //this works waaaaaay faster with 7z archive - if (sevenZipEntries.ContainsKey(filename)) - filedata = new MemoryStream(sevenZipEntries[filename]); - } else { - IArchive archive = ArchiveFactory.Open(location.location); - foreach (var entry in archive.Entries) { - if (!entry.IsDirectory) { - // Is this the entry we are looking for? - string entryname = entry.FilePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - if (string.Compare(entryname, filename, true) == 0) { - filedata = new MemoryStream(); - entry.WriteTo(filedata); - break; - } + //mxd. This works waaaaaay faster with 7z archive + if (archivetype == ArchiveType.SevenZip) + { + if (sevenzipentries.ContainsKey(filename)) + filedata = new MemoryStream(sevenzipentries[filename]); + } + else + { + UpdateArchive(true); + + foreach (var entry in archive.Entries) + { + if (entry.IsDirectory) continue; + + // Is this the entry we are looking for? + string entryname = entry.FilePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + if (string.Compare(entryname, filename, true) == 0) + { + filedata = new MemoryStream(); + entry.WriteTo(filedata); + break; } } + + UpdateArchive(false); } // Nothing found? - if (filedata == null){ + if (filedata == null) + { //mxd - General.ErrorLogger.Add(ErrorType.Error, "Cannot find the file " + filename + " in archive " + location.location + "."); - return new MemoryStream(); + General.ErrorLogger.Add(ErrorType.Error, "Cannot find the file '" + filename + "' in archive '" + location.location + "'."); + return null; } filedata.Position = 0; //mxd. rewind before use @@ -401,12 +442,6 @@ namespace CodeImp.DoomBuilder.Data filedata.Dispose(); return tempfile; } - - // Public version to load a file - internal MemoryStream ExtractFile(string filename) - { - return LoadFile(filename); - } #endregion }