Cache the global mix database in MixLoader

We can reuse this global database as it doesn't change, rather than loading a new copy each time a new mix file is parsed.
This commit is contained in:
RoosterDragon
2022-01-29 20:23:52 +00:00
committed by reaperrr
parent f5d1fe4bc4
commit d8a4d7fd1d
2 changed files with 16 additions and 17 deletions

View File

@@ -32,7 +32,7 @@ namespace OpenRA.Mods.Cnc.FileSystem
readonly long dataStart;
readonly Stream s;
public MixFile(Stream s, string filename, HashSet<string> allPossibleFilenames)
public MixFile(Stream s, string filename, string[] globalFilenames)
{
Name = filename;
this.s = s;
@@ -55,7 +55,7 @@ namespace OpenRA.Mods.Cnc.FileSystem
index = ParseIndex(entries.ToDictionaryWithConflictLog(x => x.Hash,
$"{filename} ({(isCncMix ? "C&C" : "RA/TS/RA2")} format, Encrypted: {isEncrypted}, DataStart: {dataStart})",
null, x => $"(offs={x.Offset}, len={x.Length})"), allPossibleFilenames);
null, x => $"(offs={x.Offset}, len={x.Length})"), globalFilenames);
}
catch (Exception)
{
@@ -64,10 +64,11 @@ namespace OpenRA.Mods.Cnc.FileSystem
}
}
Dictionary<string, PackageEntry> ParseIndex(Dictionary<uint, PackageEntry> entries, HashSet<string> allPossibleFilenames)
Dictionary<string, PackageEntry> ParseIndex(Dictionary<uint, PackageEntry> entries, string[] globalFilenames)
{
var classicIndex = new Dictionary<string, PackageEntry>();
var crcIndex = new Dictionary<string, PackageEntry>();
IEnumerable<string> allPossibleFilenames = globalFilenames;
// Try and find a local mix database
var dbNameClassic = PackageEntry.HashFilename("local mix database.dat", PackageHashType.Classic);
@@ -79,15 +80,14 @@ namespace OpenRA.Mods.Cnc.FileSystem
using (var content = GetContent(kv.Value))
{
var db = new XccLocalDatabase(content);
foreach (var e in db.Entries)
allPossibleFilenames.Add(e);
allPossibleFilenames = allPossibleFilenames.Concat(db.Entries);
}
break;
}
}
foreach (var filename in allPossibleFilenames)
foreach (var filename in allPossibleFilenames.Distinct())
{
var classicHash = PackageEntry.HashFilename(filename, PackageHashType.Classic);
var crcHash = PackageEntry.HashFilename(filename, PackageHashType.CRC32);
@@ -223,6 +223,8 @@ namespace OpenRA.Mods.Cnc.FileSystem
}
}
string[] globalFilenames;
bool IPackageLoader.TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package)
{
if (!filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
@@ -232,13 +234,12 @@ namespace OpenRA.Mods.Cnc.FileSystem
}
// Load the global mix database
var allPossibleFilenames = new HashSet<string>();
if (context.TryOpen("global mix database.dat", out var mixDatabase))
using (var db = new XccGlobalDatabase(mixDatabase))
foreach (var e in db.Entries)
allPossibleFilenames.Add(e);
if (globalFilenames == null)
if (context.TryOpen("global mix database.dat", out var mixDatabase))
using (var db = new XccGlobalDatabase(mixDatabase))
globalFilenames = db.Entries.Distinct().ToArray();
package = new MixFile(s, filename, allPossibleFilenames);
package = new MixFile(s, filename, globalFilenames ?? Array.Empty<string>());
return true;
}
}

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Mods.Cnc.FileFormats;
@@ -30,12 +29,11 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
[Desc("ARCHIVE.MIX", "MIXDATABASE.DAT", "Lists the content ranges for a mix file")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
var allPossibleFilenames = new HashSet<string>();
string[] globalFilenames;
using (var db = new XccGlobalDatabase(File.OpenRead(args[2])))
foreach (var e in db.Entries)
allPossibleFilenames.Add(e);
globalFilenames = db.Entries;
var package = new MixLoader.MixFile(File.OpenRead(args[1]), args[1], allPossibleFilenames);
var package = new MixLoader.MixFile(File.OpenRead(args[1]), args[1], globalFilenames);
foreach (var kv in package.Index.OrderBy(kv => kv.Value.Offset))
{
Console.WriteLine("{0}:", kv.Key);